public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
@ 2022-06-06  9:45 Philippe Waroquiers
  2022-06-06 10:53 ` Eli Zaretskii
                   ` (11 more replies)
  0 siblings, 12 replies; 17+ messages in thread
From: Philippe Waroquiers @ 2022-06-06  9:45 UTC (permalink / raw)
  To: gdb-patches

Before this patch, when a breakpoint that has multiple locations is reached,
GDB printed:
  Thread 1 "zeoes" hit Breakpoint 1, some_func () at somefunc1.c:5

This patch changes the message so that bkpt_print_id prints the precise
encountered breakpoint:
  Thread 1 "zeoes" hit Breakpoint 1.2, some_func () at somefunc1.c:5

In mi mode, bkpt_print_id also (optionally) prints a new table field "locno":
  locno is printed when the breakpoint has more than one location.
Note that according to the GDB user manual node 'GDB/MI Development and Front
Ends', it is ok to add new fields without changing the MI version.

Also, when a breakpoint is reached, the convenience variables
$bkptno and $locno are set to the encountered breakpoint number
and location number.

$bkptno and $locno can a.o. be used in the command list of a breakpoint,
to disable the specific encountered breakpoint, e.g.
   disable $bkptno.$locno

In case the breakpoint has only one location, $locno is still set to
the value 1, so as to allow a command such as:
  disable $bkptno.$locno
even when the breakpoint has only one location.

This also fixes a strange behaviour: when a breakpoint X has only
one location,
  enable|disable X.1
is accepted but transforms the breakpoint in a multiple locations
breakpoint having only one location.

The changes in RFA v3 handle the additional comments of Eli:
 GDB/NEW:
  - Use max 80-column
  - Use 'code location' instead of 'location'.
  - Fix typo $bkpno
  - Ensure that disable $bkptno and disable $bkptno.$locno have
    each their explanation inthe example
  - Reworded the 'breakpoint-hit' paragraph.
 gdb.texinfo:
  - Use 'code location' instead of 'location'.
  - Add a note to clarify the distinction between $bkptno and $bpnum.
  - Use @kbd instead of examples with only one command.

Compared to RFA v1, the changes in v2 handle the comments given by
Keith Seitz and Eli Zaretskii:
  - Use %s for the result of paddress
  - Use bkptno_numopt_re instead of 2 different -re cases
  - use C@t{++}
  - Add index entries for $bkptno and $locno
  - Added an example for "locno" in the mi interface
  - Added examples in the Break command manual.
---
 gdb/NEWS                                      | 21 +++++
 gdb/ada-lang.c                                |  2 +-
 gdb/break-catch-syscall.c                     |  2 +-
 gdb/break-catch-throw.c                       |  2 +-
 gdb/breakpoint.c                              | 93 +++++++++++++++----
 gdb/breakpoint.h                              | 14 +++
 gdb/doc/gdb.texinfo                           | 83 ++++++++++++++++-
 gdb/infrun.c                                  | 16 +++-
 gdb/testsuite/gdb.ada/bp_inlined_func.exp     |  2 +-
 gdb/testsuite/gdb.ada/operator_bp.exp         |  4 +-
 .../gdb.base/condbreak-multi-context.exp      |  8 +-
 gdb/testsuite/gdb.base/ctxobj.exp             | 26 ++++--
 gdb/testsuite/gdb.base/ena-dis-br.exp         | 41 ++++----
 gdb/testsuite/gdb.base/foll-exec-mode.exp     |  6 +-
 gdb/testsuite/gdb.base/pie-fork.exp           |  4 +-
 gdb/testsuite/gdb.base/step-over-exit.exp     |  4 +-
 gdb/testsuite/gdb.cp/mb-inline.exp            |  4 +-
 gdb/testsuite/gdb.cp/mb-templates.exp         |  6 +-
 gdb/testsuite/gdb.cp/ovldbreak.exp            |  6 +-
 gdb/testsuite/gdb.gdb/python-helper.exp       |  4 +-
 .../gdb.mi/interrupt-thread-group.exp         |  2 +-
 .../gdb.mi/user-selected-context-sync.exp     | 35 +++++--
 gdb/testsuite/gdb.multi/multi-arch-exec.exp   |  3 +-
 .../gdb.multi/run-only-second-inf.exp         |  2 +-
 .../gdb.multi/watchpoint-multi-exit.exp       |  4 +-
 gdb/testsuite/gdb.multi/watchpoint-multi.exp  |  4 +-
 gdb/testsuite/lib/gdb.exp                     | 11 ++-
 gdb/testsuite/lib/mi-support.exp              | 20 +++-
 28 files changed, 335 insertions(+), 94 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 960f90b4387..a5602deee2b 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -34,6 +34,21 @@
      whitespace from each line before using the string as the help
      output.
 
+* When a breakpoint with multiple code locations is hit, GDB now prints
+  the code location using the syntax <breakpoint_number>.<location_number>
+  such as in:
+     Thread 1 "zeoes" hit Breakpoint 2.3, some_func () at zeoes.c:8
+
+* When a breakpoint is hit, GDB now sets the convenience variables $bkptno and
+  $locno to the hit breakpoint number and code location number.
+  This allows to disable the last hit breakpoint using
+     (gdb) disable $bkptno
+   or disable only the specific breakpoint code location using
+     (gdb) disable $bkptno.$locno
+  These commands can be used inside the command list of a breakpoint to
+  automatically disable the just encountered breakpoint (or the just
+  encountered specific breakpoint code location).
+
 * New commands
 
 maintenance set ignore-prologue-end-flag on|off
@@ -50,6 +65,12 @@ maintenance info line-table
   entry corresponds to an address where a breakpoint should be placed
   to be at the first instruction past a function's prologue.
 
+* MI changes
+
+ ** The async record stating the stopped reason 'breakpoint-hit' now
+    contains an optional field locno giving the code location number
+    when the breakpoint has multiple code locations.
+
 * Python API
 
   ** New function gdb.format_address(ADDRESS, PROGSPACE, ARCHITECTURE),
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 6ab01fd27d4..bbae76f39ac 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -12348,7 +12348,7 @@ ada_catchpoint::print_it (const bpstat *bs) const
 
   uiout->text (disposition == disp_del
 	       ? "\nTemporary catchpoint " : "\nCatchpoint ");
-  uiout->field_signed ("bkptno", number);
+  print_num_locno (bs, uiout);
   uiout->text (", ");
 
   /* ada_exception_name_addr relies on the selected frame being the
diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
index 06d48466de7..82229de33f7 100644
--- a/gdb/break-catch-syscall.c
+++ b/gdb/break-catch-syscall.c
@@ -218,7 +218,7 @@ syscall_catchpoint::print_it (const bpstat *bs) const
 						: EXEC_ASYNC_SYSCALL_RETURN));
       uiout->field_string ("disp", bpdisp_text (b->disposition));
     }
-  uiout->field_signed ("bkptno", b->number);
+  print_num_locno (bs, uiout);
 
   if (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY)
     uiout->text (" (call to syscall ");
diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
index 66cf80be1c5..5b6f5d9eca1 100644
--- a/gdb/break-catch-throw.c
+++ b/gdb/break-catch-throw.c
@@ -257,7 +257,7 @@ exception_catchpoint::print_it (const bpstat *bs) const
   bp_temp = disposition == disp_del;
   uiout->text (bp_temp ? "Temporary catchpoint "
 		       : "Catchpoint ");
-  uiout->field_signed ("bkptno", number);
+  print_num_locno (bs, uiout);
   uiout->text ((kind == EX_EVENT_THROW ? " (exception thrown), "
 		: (kind == EX_EVENT_CATCH ? " (exception caught), "
 		   : " (exception rethrown), ")));
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index ed932a19ed7..c89c800f32f 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -820,6 +820,19 @@ get_breakpoint (int num)
   return nullptr;
 }
 
+/* Return TRUE if NUM refer to an existing breakpoint that has
+   multiple code locations.  */
+
+static bool
+has_multiple_locations (int num)
+{
+  for (breakpoint *b : all_breakpoints ())
+    if (b->number == num)
+      return b->loc != nullptr && b->loc->next != nullptr;
+
+  return false;
+}
+
 \f
 
 /* Mark locations as "conditions have changed" in case the target supports
@@ -4451,15 +4464,7 @@ bpstat_explains_signal (bpstat *bsp, enum gdb_signal sig)
   return false;
 }
 
-/* Put in *NUM the breakpoint number of the first breakpoint we are
-   stopped at.  *BSP upon return is a bpstat which points to the
-   remaining breakpoints stopped at (but which is not guaranteed to be
-   good for anything but further calls to bpstat_num).
-
-   Return 0 if passed a bpstat which does not indicate any breakpoints.
-   Return -1 if stopped at a breakpoint that has been deleted since
-   we set it.
-   Return 1 otherwise.  */
+/* See breakpoint.h.  */
 
 int
 bpstat_num (bpstat **bsp, int *num)
@@ -4481,6 +4486,57 @@ bpstat_num (bpstat **bsp, int *num)
   return 1;
 }
 
+/* See breakpoint.h  */
+
+int
+bpstat_locno (const bpstat *bs)
+{
+  const struct breakpoint *b = bs->breakpoint_at;
+  const struct bp_location *bl = bs->bp_location_at.get ();
+
+  int locno = 0;
+
+  if (b != nullptr && b->loc->next != nullptr)
+    {
+      const bp_location *bl_i;
+
+      for (bl_i = b->loc;
+	   bl_i != bl && bl_i->next != nullptr;
+	   bl_i = bl_i->next)
+	locno++;
+
+      if (bl_i == bl)
+	locno++;
+      else
+	{
+	  warning (_("location number not found for breakpoint %d address %s."),
+		   b->number, paddress (bl->gdbarch, bl->address));
+	  locno = 0;
+	}
+    }
+
+  return locno;
+}
+
+/* See breakpoint.h.  */
+
+void
+print_num_locno (const bpstat *bs, struct ui_out *uiout)
+{
+  struct breakpoint *b = bs->breakpoint_at;
+
+  if (b == nullptr)
+    uiout->text (_("deleted breakpoint"));
+  else
+    {
+      uiout->field_signed ("bkptno", b->number);
+
+      int locno = bpstat_locno (bs);
+      if (locno != 0)
+	uiout->message (".%pF", signed_field ("locno", locno));
+    }
+}
+
 /* See breakpoint.h.  */
 
 void
@@ -9176,7 +9232,7 @@ ranged_breakpoint::print_it (const bpstat *bs) const
 		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
       uiout->field_string ("disp", bpdisp_text (disposition));
     }
-  uiout->field_signed ("bkptno", number);
+  print_num_locno (bs, uiout);
   uiout->text (", ");
 
   return PRINT_SRC_AND_LOC;
@@ -11610,12 +11666,13 @@ ordinary_breakpoint::print_it (const bpstat *bs) const
 			   async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
       uiout->field_string ("disp", bpdisp_text (disposition));
     }
+
   if (bp_temp)
-    uiout->message ("Temporary breakpoint %pF, ",
-		    signed_field ("bkptno", number));
+    uiout->text ("Temporary breakpoint ");
   else
-    uiout->message ("Breakpoint %pF, ",
-		    signed_field ("bkptno", number));
+    uiout->text ("Breakpoint ");
+  print_num_locno (bs, uiout);
+  uiout->text (", ");
 
   return PRINT_SRC_AND_LOC;
 }
@@ -13220,9 +13277,13 @@ enable_disable_command (const char *args, int from_tty, bool enable)
 	  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)
+	      && (bp_loc_range.first == 0
+		  || (bp_loc_range.first == 1
+		      && bp_num_range.first == bp_num_range.second
+		      && !has_multiple_locations (bp_num_range.first))))
 	    {
-	      /* Handle breakpoint ids with formats 'x' or 'x-z'.  */
+	      /* Handle breakpoint ids with formats 'x' or 'x-z'
+		 or 'y.1' where y has only one code location.  */
 	      map_breakpoint_number_range (bp_num_range,
 					   enable
 					   ? enable_breakpoint
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 566f1285e46..96d61ef5427 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1231,6 +1231,20 @@ extern enum print_stop_action bpstat_print (bpstat *, int);
    Return 1 otherwise.  */
 extern int bpstat_num (bpstat **, int *);
 
+/* If BS indicates a breakpoint and this breakpoint has several code locations,
+   return the location number of BS, otherwise return 0.  */
+
+extern int bpstat_locno (const bpstat *bs);
+
+/* Print BS breakpoint number optionally followed by a . and breakpoint locno.
+
+   For a breakpoint with only one code location, outputs the signed field
+   "bkptno" breakpoint number of BS (as returned by bpstat_num).
+   If BS has several code locations, outputs a '.' character followed by
+   the signed field "locno" (as returned by bpstat_locno).  */
+
+extern void print_num_locno (const bpstat *bs, struct ui_out *);
+
 /* Perform actions associated with the stopped inferior.  Actually, we
    just use this for breakpoint commands.  Perhaps other actions will
    go here later, but this is executed at a late time (from the
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 434add3a663..391b81f8863 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4338,9 +4338,65 @@ are operated on.
 @cindex latest breakpoint
 Breakpoints are set with the @code{break} command (abbreviated
 @code{b}).  The debugger convenience variable @samp{$bpnum} records the
-number of the breakpoint you've set most recently; see @ref{Convenience
-Vars,, Convenience Variables}, for a discussion of what you can do with
-convenience variables.
+number of the breakpoint you've set most recently:
+@smallexample
+(gdb) b main
+Breakpoint 1 at 0x11c6: file zeoes.c, line 24.
+(gdb) p $bpnum
+$1 = 1
+@end smallexample
+
+A breakpoint may be mapped to multiple code locations for example with
+inlined functions, Ada generics, C@t{++} templates or overloaded function names.
+@value{GDBN} then indicates the number of code locations in the breakpoint
+command output:
+@smallexample
+(gdb) b some_func
+Breakpoint 2 at 0x1179: some_func. (3 locations)
+(gdb) p $bpnum
+$2 = 2
+(gdb)
+@end smallexample
+
+@vindex $bkptno@r{, convenience variable}
+@vindex $locno@r{, convenience variable}
+When your program stops on a breakpoint, the convenience variables
+@samp{$bkptno} and @samp{$locno} are respectively set to the number of
+the encountered breakpoint and the number of the breakpoint's code location:
+@smallexample
+Thread 1 "zeoes" hit Breakpoint 2.1, some_func () at zeoes.c:8
+8	  printf("some func\n");
+(gdb) p $bkptno
+$5 = 2
+(gdb) p $locno
+$6 = 1
+(gdb)
+@end smallexample
+
+Note that @samp{$bkptno} and @samp{$bpnum} are not equivalent:
+@samp{$bkptno} is set to the breakpoint number @b{last hit}, while
+@samp{$bpnum} is set to the breakpoint number @b{last set}.
+
+
+If the encountered breakpoint has only one code location, @samp{$locno} is set
+to 1:
+@smallexample
+Breakpoint 1, main (argc=1, argv=0x7fffffffe018) at zeoes.c:24
+24	  if (argc > 1)
+(gdb) p $bkptno
+$3 = 1
+(gdb) p $locno
+$4 = 1
+(gdb)
+@end smallexample
+
+The @samp{$bkptno} and @samp{$locno} variables can typically be used
+in a breakpoint command list.
+(@pxref{Break Commands, ,Breakpoint Command Lists}). For example, as
+part of the breakpoint command list, you can disable completely the
+encountered breakpoint using @samp{disable $bkptno} or disable the
+specific encountered breakpoint location using @samp{disable
+$bkptno.$locno}.
 
 @table @code
 @item break @var{locspec}
@@ -5739,6 +5795,13 @@ Expressions}).
 Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
 disabled within a @var{command-list}.
 
+Inside a command list, you can use the command
+@kbd{disable $bkptno} to disable the encountered breakpoint.
+
+If your breakpoint has several code locations, the command
+@kbd{disable $bkptno.$locno} will disable the specific breakpoint code
+location encountered.
+
 You can use breakpoint commands to start your program up again.  Simply
 use the @code{continue} command, or @code{step}, or any other command
 that resumes execution.
@@ -32570,6 +32633,20 @@ line="13",arch="i386:x86_64"@}
 (gdb)
 @end smallexample
 
+For a @samp{breakpoint-hit} stopped reason, when the breakpoint
+encountered has multiple locations, the field @samp{bkptno} is
+followed by the field @samp{locno}.
+
+@smallexample
+-exec-continue
+^running
+(gdb)
+@@Hello world
+*stopped,reason="breakpoint-hit",disp="keep",bkptno="2",locno="3",frame=@{
+func="foo",args=[],file="hello.c",fullname="/home/foo/bar/hello.c",
+line="13",arch="i386:x86_64"@}
+(gdb)
+@end smallexample
 
 @subheading The @code{-exec-finish} Command
 @findex -exec-finish
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 02c98b50c8c..e5ad062a914 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -8494,7 +8494,21 @@ print_stop_location (const target_waitstatus &ws)
      LOCATION: Print only location
      SRC_AND_LOC: Print location and source line.  */
   if (do_frame_printing)
-    print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
+    {
+      if (tp->control.stop_bpstat != nullptr)
+	{
+	  const struct breakpoint *b = tp->control.stop_bpstat->breakpoint_at;
+
+	  if (b != nullptr)
+	    {
+	      int locno = bpstat_locno (tp->control.stop_bpstat);
+	      set_internalvar_integer (lookup_internalvar ("bkptno"), b->number);
+	      set_internalvar_integer (lookup_internalvar ("locno"),
+				       (locno > 0 ? locno : 1));
+	    }
+	}
+      print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
+    }
 }
 
 /* See infrun.h.  */
diff --git a/gdb/testsuite/gdb.ada/bp_inlined_func.exp b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
index 076e8c2425f..3f94c163819 100644
--- a/gdb/testsuite/gdb.ada/bp_inlined_func.exp
+++ b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
@@ -42,7 +42,7 @@ gdb_test "break read_small" \
 for {set i 0} {$i < 4} {incr i} {
     with_test_prefix "iteration $i" {
 	gdb_test "continue" \
-	    "Breakpoint $decimal, b\\.read_small \\(\\).*" \
+	    "Breakpoint $bkptno_num_re, b\\.read_small \\(\\).*" \
 	    "stopped in read_small"
     }
 }
diff --git a/gdb/testsuite/gdb.ada/operator_bp.exp b/gdb/testsuite/gdb.ada/operator_bp.exp
index 655e7af479f..e3928419ed6 100644
--- a/gdb/testsuite/gdb.ada/operator_bp.exp
+++ b/gdb/testsuite/gdb.ada/operator_bp.exp
@@ -56,7 +56,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
 foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
     set op_re [string_to_regexp $op]
     gdb_test "continue" \
-             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
+             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
              "continue to \"$op\""
 }
 
@@ -86,7 +86,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
 foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
     set op_re [string_to_regexp $op]
     gdb_test "continue" \
-             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
+             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
              "continue to ops.\"$op\""
 }
 
diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
index b540df973a3..742315178e3 100644
--- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp
+++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
@@ -140,11 +140,11 @@ with_test_prefix "scenario 1" {
     gdb_run_cmd
 
     # Check our conditional breakpoints.
-    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
+    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
 	"run until A::func"
     gdb_test "print a" " = 10"
 
-    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
+    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
 	"run until C::func"
     gdb_test "print c" " = 30"
 
@@ -208,11 +208,11 @@ with_test_prefix "scenario 2" {
     gdb_run_cmd
 
     # Check that we hit enabled locations only.
-    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
+    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
 	"run until A::func"
     gdb_test "print a" " = 10"
 
-    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
+    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
 	"run until C::func"
     gdb_test "print c" " = 30"
 
diff --git a/gdb/testsuite/gdb.base/ctxobj.exp b/gdb/testsuite/gdb.base/ctxobj.exp
index 9c010f54d79..0b589a7d6e6 100644
--- a/gdb/testsuite/gdb.base/ctxobj.exp
+++ b/gdb/testsuite/gdb.base/ctxobj.exp
@@ -67,9 +67,16 @@ gdb_test "break ctxobj-f.c:$bp_location" \
          "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
          "break in get_version functions"
 
-gdb_test "continue" \
-         "Breakpoint $decimal, get_version_1 \\(\\).*" \
-         "continue to get_version_1"
+global expect_out
+set test "continue to get_version_1"
+gdb_test_multiple "continue" $test {
+    -re "Breakpoint ($bkptno_num_re), get_version_1 \\(\\).*" {
+	set bpno $expect_out(1,string)
+	pass $test
+    }
+}
+# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
+gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
 
 # Try printing "this_version_num".  There are two global variables
 # with that name, and some systems such as GNU/Linux merge them
@@ -100,10 +107,15 @@ gdb_test "print this_version_num == v" \
         "print libctxobj1's this_version_num from symtab"
 
 # Do the same, but from get_version_2.
-
-gdb_test "continue" \
-         "Breakpoint $decimal, get_version_2 \\(\\).*" \
-         "continue to get_version_2"
+set test "continue to get_version_2"
+gdb_test_multiple "continue" $test {
+    -re "Breakpoint ($bkptno_num_re), get_version_2 \\(\\).*" {
+	set bpno $expect_out(1,string)
+	pass $test
+    }
+}
+# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
+gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
 
 gdb_test "print this_version_num == v" \
          " = 1" \
diff --git a/gdb/testsuite/gdb.base/ena-dis-br.exp b/gdb/testsuite/gdb.base/ena-dis-br.exp
index 24925cf7185..04b3f134b44 100644
--- a/gdb/testsuite/gdb.base/ena-dis-br.exp
+++ b/gdb/testsuite/gdb.base/ena-dis-br.exp
@@ -67,14 +67,21 @@ gdb_test "info break $bp" \
 # See the comments in condbreak.exp for "run until breakpoint at
 # marker1" for an explanation of the xfail below.
 set test "continue to break marker1"
+set bpno 0
 gdb_test_multiple "continue" "$test" {
-    -re "Breakpoint \[0-9\]*, marker1.*$gdb_prompt $" {
+    -re "Breakpoint (\[0-9\]*), marker1.*$gdb_prompt $" {
+	set bpno $expect_out(1,string)
 	pass "$test"
     }
-    -re "Breakpoint \[0-9\]*, $hex in marker1.*$gdb_prompt $" {
+    -re "Breakpoint (\[0-9\]*), $hex in marker1.*$gdb_prompt $" {
+	set bpno $expect_out(1,string)
 	xfail "$test"
     }
 }
+# Verify the $bkptno convenience variable is equal to the hit bpno.
+gdb_test "print \$bkptno" " = $bpno" "$test \$bkptno is $bpno"
+# Verify the $locno is 1, as there is only one code location.
+gdb_test "print \$locno" " = 1" "$test \$locno is 1"
 
 gdb_test_no_output "delete $bp" "delete break marker1"
 
@@ -359,7 +366,8 @@ with_test_prefix "4th breakpoint" {
 }
 
 # Perform tests for disable/enable commands on multiple
-# locations and breakpoints.
+# code locations and breakpoints.  If a breakpoint has only one code location,
+# enable/disable num  and enable/disable num.1 should be equivalent.
 #
 # WHAT - the command to test (disable/enable).
 #
@@ -372,7 +380,7 @@ proc test_ena_dis_br { what } {
     global b3
     global b4
     global gdb_prompt
-    
+
     # OPPOS    - the command opposite to WHAT.
     # WHAT_RES - whether breakpoints are expected to end
     #            up enabled or disabled.
@@ -395,13 +403,13 @@ proc test_ena_dis_br { what } {
 	set p2 "pass"
     }
 
-    # Now enable(disable) $b.1 $b2.1.
+    # Now enable(disable) $b1.1 $b2.1.
     gdb_test_no_output "$what $b1.1 $b2.1" "$what \$b1.1 \$b2.1"
     set test1 "${what}d \$b1.1 and \$b2.1"
 
     # Now $b1.1 and $b2.1 should be enabled(disabled).
     gdb_test_multiple "info break" "$test1" {
-       -re "(${b1}.1)(\[^\n\r\]*)( n.*)(${b2}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
+       -re "(${b1})(\[^\n\r\]*)( n.*)(${b2})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
            $p1 "$test1"
        }
        -re ".*$gdb_prompt $" {
@@ -420,19 +428,16 @@ proc test_ena_dis_br { what } {
        "${what}d \$b1"
 
     gdb_test_no_output "$oppos $b3" "$oppos \$b3"
+    # Now $b4 $b3 should be enabled(disabled)
+    set test1 "${what}d \$b4 and \$b3"
+    gdb_test "info break" "(${b3})(\[^\n\r]*)( $oppos_res.*).*(${b4})(\[^\n\r\]*)( $oppos_res.*)" "$test1"
+
     gdb_test_no_output "$what $b4 $b3.1" "$what \$b4 \$b3.1"
-    set test1 "${what}d \$b4 and \$b3.1,remain ${oppos}d \$b3"
+    set test1 "${what}d \$b4 and \$b3.1, changing \$b3"
+
+    # Now $b4 $b3 should be enabled(disabled)
+    gdb_test "info break" "(${b3})(\[^\n\r]*)( $what_res.*).*(${b4})(\[^\n\r\]*)( $what_res.*)" "$test1"
 
-    # Now $b4 $b3.1 should be enabled(disabled) and
-    # $b3 should remain disabled(enabled).
-    gdb_test_multiple "info break" "$test1" {
-       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b3}.1)(\[^\n\r\]*)( n.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
-           $p1 "$test1"
-       }
-       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
-           $p2 "$test1"
-       }
-    }
 
     # Now enable(disable) '$b4.1 fooobaar'.  This should error on
     # fooobaar.
@@ -443,7 +448,7 @@ proc test_ena_dis_br { what } {
 
     # $b4.1 should be enabled(disabled).
     gdb_test_multiple "info break" "$test1" {
-        -re "(${b4}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
+        -re "(${b4})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
            $p1 "$test1"
        }
        -re ".*$gdb_prompt $" {
diff --git a/gdb/testsuite/gdb.base/foll-exec-mode.exp b/gdb/testsuite/gdb.base/foll-exec-mode.exp
index 918f3e4fd5f..cb6d975a767 100644
--- a/gdb/testsuite/gdb.base/foll-exec-mode.exp
+++ b/gdb/testsuite/gdb.base/foll-exec-mode.exp
@@ -99,7 +99,7 @@ proc do_catch_exec_test { } {
 # before re-running.
 
 proc do_follow_exec_mode_tests { mode cmd infswitch } {
-    global binfile srcfile srcfile2 testfile testfile2
+    global binfile srcfile srcfile2 testfile testfile2 bkptno_numopt_re
     global gdb_prompt
 
     with_test_prefix "$mode,$cmd,$infswitch" {
@@ -125,7 +125,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
 	# Set up the output we expect to see after we execute past the exec.
 	#
 	set execd_line [gdb_get_line_number "after-exec" $srcfile2]
-	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint .,.*${srcfile2}:${execd_line}.*$gdb_prompt $"
+	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint ${bkptno_numopt_re},.*${srcfile2}:${execd_line}.*$gdb_prompt $"
 
 	# Set a breakpoint after the exec call if we aren't single-stepping
 	# past it.
@@ -189,7 +189,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
 		send_gdb "y\n"
 		exp_continue
 	    }
-	    -re "Starting program: .*$expected_inf.*Breakpoint .,.*\r\n$gdb_prompt $" {
+	    -re "Starting program: .*$expected_inf.*Breakpoint $bkptno_numopt_re,.*\r\n$gdb_prompt $" {
 		pass $test
 	    }
 	}
diff --git a/gdb/testsuite/gdb.base/pie-fork.exp b/gdb/testsuite/gdb.base/pie-fork.exp
index efc357d39a2..19e9d3a5537 100644
--- a/gdb/testsuite/gdb.base/pie-fork.exp
+++ b/gdb/testsuite/gdb.base/pie-fork.exp
@@ -54,10 +54,10 @@ proc_with_prefix test_detach_on_fork_follow_child {} {
 proc_with_prefix test_no_detach_on_fork {} {
     setup_test "off"
 
-    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2, break_here.*" \
+    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2.1, break_here.*" \
 	     "continue from thread 1.1"
     gdb_test "thread 2.1"
-    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2, break_here.*" \
+    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2.2, break_here.*" \
 	     "continue from thread 2.1"
 }
 
diff --git a/gdb/testsuite/gdb.base/step-over-exit.exp b/gdb/testsuite/gdb.base/step-over-exit.exp
index f8bd99980fe..575319c564c 100644
--- a/gdb/testsuite/gdb.base/step-over-exit.exp
+++ b/gdb/testsuite/gdb.base/step-over-exit.exp
@@ -91,7 +91,7 @@ delete_breakpoints
 
 gdb_test "break marker"
 
-gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
+gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_num_re, .*" \
     "continue to marker, first time"
 
 # Step 2, create a breakpoint which evaluates false, and force it
@@ -120,5 +120,5 @@ gdb_test "inferior 1" ".*Switching to inferior 1.*" \
 # Switch back to the parent process, continue to the marker to
 # test GDBserver's state is still correct.
 
-gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
+gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_numopt_re, .*" \
     "continue to marker, second time"
diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
index 47a2a5dcb7c..fa098602c31 100644
--- a/gdb/testsuite/gdb.cp/mb-inline.exp
+++ b/gdb/testsuite/gdb.cp/mb-inline.exp
@@ -46,7 +46,7 @@ gdb_test "info break" \
     "\[\r\n\]1\.1.* y .* at .*$hdrfile:$bp_location.*\[\r\n\]1\.2.* y .* at .*$hdrfile:$bp_location.*"
 
 gdb_run_cmd
-gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "run to breakpoint"
+gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "run to breakpoint"
 
 gdb_test "continue" \
     ".*Breakpoint.*foo \\(i=1\\).*" \
@@ -59,7 +59,7 @@ gdb_test "continue" \
 gdb_test_no_output "disable 1.2" "disabling location: disable"
 
 gdb_run_cmd
-gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
+gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
 
 gdb_test_multiple "info break" "disabled breakpoint 1.2" {
     -re "1\.2.* n .* at .*$hdrfile:$bp_location.*$gdb_prompt $" {
diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
index 6c988e7335e..0c0d46fcb7a 100644
--- a/gdb/testsuite/gdb.cp/mb-templates.exp
+++ b/gdb/testsuite/gdb.cp/mb-templates.exp
@@ -42,7 +42,7 @@ gdb_run_cmd
 
 set test "initial condition: run to breakpoint"
 gdb_test_multiple "" $test {
-    -re "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
+    -re "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
 	pass $test
 	break
     }
@@ -67,7 +67,7 @@ gdb_test_no_output {condition $bpnum i==1} \
     "separate condition: set condition"
     
 gdb_run_cmd
-gdb_test "" "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
+gdb_test "" "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
 
 gdb_test "continue" \
     ".*Breakpoint.*foo<double> \\(i=1\\).*" \
@@ -79,7 +79,7 @@ gdb_test "continue" \
 gdb_test_no_output {disable $bpnum.1} "disabling location: disable"
 
 gdb_run_cmd
-gdb_test "" "Breakpoint \[0-9\]+,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
+gdb_test "" "Breakpoint $bkptno_num_re,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
 
 # Try disabling entire breakpoint
 gdb_test_no_output {enable $bpnum.1} "disabling location: enable"
diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
index 06adf82ecbb..0ed9eae055b 100644
--- a/gdb/testsuite/gdb.cp/ovldbreak.exp
+++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
@@ -380,7 +380,7 @@ gdb_test "info break" $bptable "breakpoint info (after setting on all)"
 
 # Run through each breakpoint.
 proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
-    global gdb_prompt hex decimal srcfile
+    global gdb_prompt hex decimal srcfile bkptno_num_re
 
     if {$argument == ""} {
         set actuals ""
@@ -398,11 +398,11 @@ proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
     }
 
     gdb_test_multiple "continue" "continue to bp overloaded : $argtype" {
-        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
+        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
             pass "continue to bp overloaded : $argtype"
         }
 
-        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
+        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
             if $might_kfail {
                 kfail "c++/8130" "continue to bp overloaded : $argtype"
             } else {
diff --git a/gdb/testsuite/gdb.gdb/python-helper.exp b/gdb/testsuite/gdb.gdb/python-helper.exp
index 6db8bf0df50..30eb6038f3a 100644
--- a/gdb/testsuite/gdb.gdb/python-helper.exp
+++ b/gdb/testsuite/gdb.gdb/python-helper.exp
@@ -49,7 +49,7 @@ gdb_exit
 # The main test.  This is called by the self-test framework once GDB
 # has been started on a copy of itself.
 proc test_python_helper {} {
-    global py_helper_script decimal hex gdb_prompt
+    global py_helper_script decimal hex gdb_prompt bkptno_numopt_re
     global inferior_spawn_id
 
     # Source the python helper script.  This script registers the
@@ -233,7 +233,7 @@ proc test_python_helper {} {
     # GDB stopping at the value_print breakpoint again.
     send_inferior "ptype global_c\n"
     gdb_test_multiple "" "hit breakpoint in outer gdb again" {
-	-re "Breakpoint $decimal, c_print_type .*\\(outer-gdb\\) $" {
+	-re "Breakpoint $bkptno_numopt_re, c_print_type .*\\(outer-gdb\\) $" {
 	    pass $gdb_test_name
 	}
     }
diff --git a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
index 19ccbe85e04..c080955049c 100644
--- a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
+++ b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
@@ -69,7 +69,7 @@ if { $use_second_inferior } {
 	"\\^running.*" \
 	"run inferior 2"
 
-    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\""} \
+    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\"" "locno=\"[0-9]+\""} \
 	"inferior i2 stops at all_threads_started"
 
     mi_send_resuming_command "exec-continue --thread-group i2" \
diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
index d78c96ddef1..9eec083068b 100644
--- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
+++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
@@ -307,8 +307,13 @@ proc test_continue_to_start { mode inf } {
 
 	    # Consume MI event output.
 	    with_spawn_id $mi_spawn_id {
-		mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
-		    "$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
+		if { $inf == 1 } {
+		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
+			"$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
+		} else {
+		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
+			"$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} "stop at breakpoint in main"
+		}
 	    }
 
 	    if { $mode == "all-stop" } {
@@ -330,9 +335,15 @@ proc test_continue_to_start { mode inf } {
 
 		    # Consume MI output.
 		    with_spawn_id $mi_spawn_id {
-			mi_expect_stop "breakpoint-hit" "child_sub_function" \
-			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
-			    "thread $inf.$thread stops MI"
+			if { $inf == 1} {
+			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
+				"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
+				"thread $inf.$thread stops MI"
+			} else {
+			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
+				"" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
+				"thread $inf.$thread stops MI"
+			}
 		    }
 		}
 
@@ -359,9 +370,15 @@ proc test_continue_to_start { mode inf } {
 
 		# Consume MI output.
 		with_spawn_id $mi_spawn_id {
-		    mi_expect_stop "breakpoint-hit" "child_sub_function" \
-			"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
-			"thread $inf.2 stops MI"
+		    if { $inf == 1} {
+			mi_expect_stop "breakpoint-hit" "child_sub_function" \
+			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
+			    "thread $inf.2 stops MI"
+		    } else {
+			mi_expect_stop "breakpoint-hit" "child_sub_function" \
+			    "" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
+			    "thread $inf.2 stops MI"
+		    }
 		}
 	    }
 	}
@@ -434,7 +451,7 @@ proc_with_prefix test_setup { mode } {
 
 	with_spawn_id $mi_spawn_id {
 	    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" "$decimal" \
-		{"" "disp=\"del\""} "main stop"
+		{"" "disp=\"del\"" "locno=\"[0-9]+\""} "main stop"
 	}
 
 	# Consume CLI output.
diff --git a/gdb/testsuite/gdb.multi/multi-arch-exec.exp b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
index a1496fb5571..dfdb746c65e 100644
--- a/gdb/testsuite/gdb.multi/multi-arch-exec.exp
+++ b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
@@ -148,6 +148,7 @@ proc build_executables { first_arch } {
 }
 
 proc do_test { first_arch mode selected_thread } {
+        global bkptno_numopt_re
 	set from_exec "$first_arch-multi-arch-exec"
 
 	clean_restart ${from_exec}
@@ -169,7 +170,7 @@ proc do_test { first_arch mode selected_thread } {
 
 	# Test that GDB updates the target description / arch successfuly
 	# after the exec.
-	gdb_test "continue" "Breakpoint 2, main.*" "continue across exec that changes architecture"
+	gdb_test "continue" "Breakpoint $bkptno_numopt_re, main.*" "continue across exec that changes architecture"
 }
 
 # Test both arch1=>arch2 and arch2=>arch1.
diff --git a/gdb/testsuite/gdb.multi/run-only-second-inf.exp b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
index fec2575f904..b94689d0bfa 100644
--- a/gdb/testsuite/gdb.multi/run-only-second-inf.exp
+++ b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
@@ -46,5 +46,5 @@ gdb_load $binfile
 if {[gdb_start_cmd] < 0} {
     fail "start the second inf"
 } else {
-    gdb_test "" ".*reakpoint ., main .*${srcfile}.*" "start the second inf"
+    gdb_test "" ".*reakpoint $bkptno_numopt_re, main .*${srcfile}.*" "start the second inf"
 }
diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
index cbccba19d12..3c079facced 100644
--- a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
+++ b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
@@ -27,7 +27,7 @@ if {[build_executable "failed to build" $testfile $srcfile {debug}]} {
 # child.  Can be either "kill", "detach", or "exit" (to continue it to
 # normal exit).
 proc do_test {dispose} {
-    global binfile
+    global binfile bkptno_numopt_re
 
     clean_restart $binfile
 
@@ -77,7 +77,7 @@ proc do_test {dispose} {
     #  Command aborted.
     #  (gdb)
     #
-    gdb_test "continue" "Breakpoint \[0-9\]+, marker .*" \
+    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker .*" \
 	"continue in inferior 1"
 }
 
diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi.exp b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
index e4329dca6c2..0fc1bee762f 100644
--- a/gdb/testsuite/gdb.multi/watchpoint-multi.exp
+++ b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
@@ -84,11 +84,11 @@ if [skip_hw_watchpoint_multi_tests] {
 	"Hardware access \\(read/write\\) watchpoint \[0-9\]+: c\r\n\r\nOld value = 0\r\nNew value = 3\r\n.*" \
 	"catch c on inferior 2"
 
-    gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 2"
+    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 2"
 
     gdb_test "inferior 1" "witching to inferior 1 .*" "switch back to inferior 1 again"
 
     gdb_test "continue" "Hardware access \\(read/write\\) watchpoint \[0-9\]+: b\r\n\r\nOld value = 0\r\nNew value = 2\r\n.*" "catch b on inferior 1"
 }
 
-gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 1"
+gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 1"
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 402450152ac..5e4c793598e 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -227,6 +227,14 @@ set inferior_exited_re "(?:\\\[Inferior \[0-9\]+ \\(\[^\n\r\]*\\) exited)"
 # E.g., $1, $2, etc.
 set valnum_re "\\\$$decimal"
 
+# A regular expression that matches a breakpoint hit with a breakpoint
+# having several code locations.
+set bkptno_num_re "$decimal\\.$decimal"
+
+# A regular expression that matches a breakpoint hit
+# with one or several code locations.
+set bkptno_numopt_re "($decimal\\.$decimal|$decimal)"
+
 ### Only procedures should come after this point.
 
 #
@@ -662,6 +670,7 @@ proc gdb_breakpoint { linespec args } {
 
 proc runto { linespec args } {
     global gdb_prompt
+    global bkptno_numopt_re
     global decimal
 
     delete_breakpoints
@@ -699,7 +708,7 @@ proc runto { linespec args } {
 	    }
 	    return 1
 	}
-	-re "Breakpoint \[0-9\]*, \[0-9xa-f\]* in .*$gdb_prompt $" { 
+	-re "Breakpoint $bkptno_numopt_re, \[0-9xa-f\]* in .*$gdb_prompt $" {
 	    if { $print_pass } {
 		pass $test_name
 	    }
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index e578a7e6f9b..ea66fdcabf8 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -1195,11 +1195,11 @@ proc mi_detect_async {} {
 # filename of a file without debug info.  ARGS should not include [] the
 # list of argument is enclosed in, and other regular expressions should
 # not include quotes.
-# If EXTRA is a list of one element, it's the regular expression
+# EXTRA can be a list of one, two or three elements.
+# The first element is the regular expression
 # for output expected right after *stopped, and before GDB prompt.
-# If EXTRA is a list of two elements, the first element is for
-# output right after *stopped, and the second element is output
-# right after reason field.  The regex after reason should not include
+# The third element is the regulation expression for the locno
+# right after bkptno field.  The locno regex should not include
 # the comma separating it from the following fields.
 #
 # When we fail to match output at all, -1 is returned.  If FILE does
@@ -1224,7 +1224,14 @@ proc mi_expect_stop { reason func args file line extra test } {
 
     set after_stopped ""
     set after_reason ""
-    if { [llength $extra] == 2 } {
+    set locno ""
+    if { [llength $extra] == 3 } {
+	set after_stopped [lindex $extra 0]
+	set after_reason [lindex $extra 1]
+	set after_reason "${after_reason},"
+	set locno [lindex $extra 2]
+	set locno "${locno},"
+    } elseif { [llength $extra] == 2 } {
 	set after_stopped [lindex $extra 0]
 	set after_reason [lindex $extra 1]
 	set after_reason "${after_reason},"
@@ -1298,10 +1305,12 @@ proc mi_expect_stop { reason func args file line extra test } {
     set ebn ""
     if { $reason == "breakpoint-hit" } {
 	set bn {bkptno="[0-9]+",}
+	set bn "${bn}${locno}"
     } elseif { $reason == "solib-event" } {
 	set bn ".*"
     } elseif { $reason == "exception-caught" } {
 	set ebn {bkptno="[0-9]+",}
+	set ebn "${ebn}${locno}"
 	set bn ".*"
 	set reason "breakpoint-hit"
     }
@@ -1315,6 +1324,7 @@ proc mi_expect_stop { reason func args file line extra test } {
     set a $after_reason
 
     verbose -log "mi_expect_stop: expecting: \\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
+
     gdb_expect {
 	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
 	    pass "$test"
-- 
2.30.2


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-06-06  9:45 [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno Philippe Waroquiers
@ 2022-06-06 10:53 ` Eli Zaretskii
  2022-06-13 17:51 ` Philippe Waroquiers
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Eli Zaretskii @ 2022-06-06 10:53 UTC (permalink / raw)
  To: Philippe Waroquiers; +Cc: gdb-patches

> Date: Mon,  6 Jun 2022 11:45:04 +0200
> From: Philippe Waroquiers via Gdb-patches <gdb-patches@sourceware.org>
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 960f90b4387..a5602deee2b 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS

This part is OK.

> +The @samp{$bkptno} and @samp{$locno} variables can typically be used
> +in a breakpoint command list.
> +(@pxref{Break Commands, ,Breakpoint Command Lists}). For example, as
                                                      ^^
Two spaces there, please.

> +part of the breakpoint command list, you can disable completely the
> +encountered breakpoint using @samp{disable $bkptno} or disable the
> +specific encountered breakpoint location using @samp{disable
> +$bkptno.$locno}.

It is better to use @kbd{..} for markup of commands that the user is
supposed to type.

> +Inside a command list, you can use the command
> +@kbd{disable $bkptno} to disable the encountered breakpoint.
> +
> +If your breakpoint has several code locations, the command
> +@kbd{disable $bkptno.$locno} will disable the specific breakpoint code
> +location encountered.

Yes, like you did here.

The documentation parts are OK with these two nits fixed.

Thanks.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-06-06  9:45 [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno Philippe Waroquiers
  2022-06-06 10:53 ` Eli Zaretskii
@ 2022-06-13 17:51 ` Philippe Waroquiers
  2022-06-14 17:32   ` Keith Seitz
  2022-06-19 17:46 ` Philippe Waroquiers
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 17+ messages in thread
From: Philippe Waroquiers @ 2022-06-13 17:51 UTC (permalink / raw)
  To: gdb-patches

Ping ?

Thanks

Philippe

On Mon, 2022-06-06 at 11:45 +0200, Philippe Waroquiers wrote:
> Before this patch, when a breakpoint that has multiple locations is reached,
> GDB printed:
>   Thread 1 "zeoes" hit Breakpoint 1, some_func () at somefunc1.c:5
> 
> This patch changes the message so that bkpt_print_id prints the precise
> encountered breakpoint:
>   Thread 1 "zeoes" hit Breakpoint 1.2, some_func () at somefunc1.c:5
> 
> In mi mode, bkpt_print_id also (optionally) prints a new table field "locno":
>   locno is printed when the breakpoint has more than one location.
> Note that according to the GDB user manual node 'GDB/MI Development and Front
> Ends', it is ok to add new fields without changing the MI version.
> 
> Also, when a breakpoint is reached, the convenience variables
> $bkptno and $locno are set to the encountered breakpoint number
> and location number.
> 
> $bkptno and $locno can a.o. be used in the command list of a breakpoint,
> to disable the specific encountered breakpoint, e.g.
>    disable $bkptno.$locno
> 
> In case the breakpoint has only one location, $locno is still set to
> the value 1, so as to allow a command such as:
>   disable $bkptno.$locno
> even when the breakpoint has only one location.
> 
> This also fixes a strange behaviour: when a breakpoint X has only
> one location,
>   enable|disable X.1
> is accepted but transforms the breakpoint in a multiple locations
> breakpoint having only one location.
> 
> The changes in RFA v3 handle the additional comments of Eli:
>  GDB/NEW:
>   - Use max 80-column
>   - Use 'code location' instead of 'location'.
>   - Fix typo $bkpno
>   - Ensure that disable $bkptno and disable $bkptno.$locno have
>     each their explanation inthe example
>   - Reworded the 'breakpoint-hit' paragraph.
>  gdb.texinfo:
>   - Use 'code location' instead of 'location'.
>   - Add a note to clarify the distinction between $bkptno and $bpnum.
>   - Use @kbd instead of examples with only one command.
> 
> Compared to RFA v1, the changes in v2 handle the comments given by
> Keith Seitz and Eli Zaretskii:
>   - Use %s for the result of paddress
>   - Use bkptno_numopt_re instead of 2 different -re cases
>   - use C@t{++}
>   - Add index entries for $bkptno and $locno
>   - Added an example for "locno" in the mi interface
>   - Added examples in the Break command manual.
> ---
>  gdb/NEWS                                      | 21 +++++
>  gdb/ada-lang.c                                |  2 +-
>  gdb/break-catch-syscall.c                     |  2 +-
>  gdb/break-catch-throw.c                       |  2 +-
>  gdb/breakpoint.c                              | 93 +++++++++++++++----
>  gdb/breakpoint.h                              | 14 +++
>  gdb/doc/gdb.texinfo                           | 83 ++++++++++++++++-
>  gdb/infrun.c                                  | 16 +++-
>  gdb/testsuite/gdb.ada/bp_inlined_func.exp     |  2 +-
>  gdb/testsuite/gdb.ada/operator_bp.exp         |  4 +-
>  .../gdb.base/condbreak-multi-context.exp      |  8 +-
>  gdb/testsuite/gdb.base/ctxobj.exp             | 26 ++++--
>  gdb/testsuite/gdb.base/ena-dis-br.exp         | 41 ++++----
>  gdb/testsuite/gdb.base/foll-exec-mode.exp     |  6 +-
>  gdb/testsuite/gdb.base/pie-fork.exp           |  4 +-
>  gdb/testsuite/gdb.base/step-over-exit.exp     |  4 +-
>  gdb/testsuite/gdb.cp/mb-inline.exp            |  4 +-
>  gdb/testsuite/gdb.cp/mb-templates.exp         |  6 +-
>  gdb/testsuite/gdb.cp/ovldbreak.exp            |  6 +-
>  gdb/testsuite/gdb.gdb/python-helper.exp       |  4 +-
>  .../gdb.mi/interrupt-thread-group.exp         |  2 +-
>  .../gdb.mi/user-selected-context-sync.exp     | 35 +++++--
>  gdb/testsuite/gdb.multi/multi-arch-exec.exp   |  3 +-
>  .../gdb.multi/run-only-second-inf.exp         |  2 +-
>  .../gdb.multi/watchpoint-multi-exit.exp       |  4 +-
>  gdb/testsuite/gdb.multi/watchpoint-multi.exp  |  4 +-
>  gdb/testsuite/lib/gdb.exp                     | 11 ++-
>  gdb/testsuite/lib/mi-support.exp              | 20 +++-
>  28 files changed, 335 insertions(+), 94 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 960f90b4387..a5602deee2b 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -34,6 +34,21 @@
>       whitespace from each line before using the string as the help
>       output.
>  
> 
> +* When a breakpoint with multiple code locations is hit, GDB now prints
> +  the code location using the syntax <breakpoint_number>.<location_number>
> +  such as in:
> +     Thread 1 "zeoes" hit Breakpoint 2.3, some_func () at zeoes.c:8
> +
> +* When a breakpoint is hit, GDB now sets the convenience variables $bkptno and
> +  $locno to the hit breakpoint number and code location number.
> +  This allows to disable the last hit breakpoint using
> +     (gdb) disable $bkptno
> +   or disable only the specific breakpoint code location using
> +     (gdb) disable $bkptno.$locno
> +  These commands can be used inside the command list of a breakpoint to
> +  automatically disable the just encountered breakpoint (or the just
> +  encountered specific breakpoint code location).
> +
>  * New commands
>  
> 
>  maintenance set ignore-prologue-end-flag on|off
> @@ -50,6 +65,12 @@ maintenance info line-table
>    entry corresponds to an address where a breakpoint should be placed
>    to be at the first instruction past a function's prologue.
>  
> 
> +* MI changes
> +
> + ** The async record stating the stopped reason 'breakpoint-hit' now
> +    contains an optional field locno giving the code location number
> +    when the breakpoint has multiple code locations.
> +
>  * Python API
>  
> 
>    ** New function gdb.format_address(ADDRESS, PROGSPACE, ARCHITECTURE),
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 6ab01fd27d4..bbae76f39ac 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -12348,7 +12348,7 @@ ada_catchpoint::print_it (const bpstat *bs) const
>  
> 
>    uiout->text (disposition == disp_del
>  	       ? "\nTemporary catchpoint " : "\nCatchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    /* ada_exception_name_addr relies on the selected frame being the
> diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
> index 06d48466de7..82229de33f7 100644
> --- a/gdb/break-catch-syscall.c
> +++ b/gdb/break-catch-syscall.c
> @@ -218,7 +218,7 @@ syscall_catchpoint::print_it (const bpstat *bs) const
>  						: EXEC_ASYNC_SYSCALL_RETURN));
>        uiout->field_string ("disp", bpdisp_text (b->disposition));
>      }
> -  uiout->field_signed ("bkptno", b->number);
> +  print_num_locno (bs, uiout);
>  
> 
>    if (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY)
>      uiout->text (" (call to syscall ");
> diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
> index 66cf80be1c5..5b6f5d9eca1 100644
> --- a/gdb/break-catch-throw.c
> +++ b/gdb/break-catch-throw.c
> @@ -257,7 +257,7 @@ exception_catchpoint::print_it (const bpstat *bs) const
>    bp_temp = disposition == disp_del;
>    uiout->text (bp_temp ? "Temporary catchpoint "
>  		       : "Catchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text ((kind == EX_EVENT_THROW ? " (exception thrown), "
>  		: (kind == EX_EVENT_CATCH ? " (exception caught), "
>  		   : " (exception rethrown), ")));
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index ed932a19ed7..c89c800f32f 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -820,6 +820,19 @@ get_breakpoint (int num)
>    return nullptr;
>  }
>  
> 
> +/* Return TRUE if NUM refer to an existing breakpoint that has
> +   multiple code locations.  */
> +
> +static bool
> +has_multiple_locations (int num)
> +{
> +  for (breakpoint *b : all_breakpoints ())
> +    if (b->number == num)
> +      return b->loc != nullptr && b->loc->next != nullptr;
> +
> +  return false;
> +}
> +
>  \f
>  
> 
>  /* Mark locations as "conditions have changed" in case the target supports
> @@ -4451,15 +4464,7 @@ bpstat_explains_signal (bpstat *bsp, enum gdb_signal sig)
>    return false;
>  }
>  
> 
> -/* Put in *NUM the breakpoint number of the first breakpoint we are
> -   stopped at.  *BSP upon return is a bpstat which points to the
> -   remaining breakpoints stopped at (but which is not guaranteed to be
> -   good for anything but further calls to bpstat_num).
> -
> -   Return 0 if passed a bpstat which does not indicate any breakpoints.
> -   Return -1 if stopped at a breakpoint that has been deleted since
> -   we set it.
> -   Return 1 otherwise.  */
> +/* See breakpoint.h.  */
>  
> 
>  int
>  bpstat_num (bpstat **bsp, int *num)
> @@ -4481,6 +4486,57 @@ bpstat_num (bpstat **bsp, int *num)
>    return 1;
>  }
>  
> 
> +/* See breakpoint.h  */
> +
> +int
> +bpstat_locno (const bpstat *bs)
> +{
> +  const struct breakpoint *b = bs->breakpoint_at;
> +  const struct bp_location *bl = bs->bp_location_at.get ();
> +
> +  int locno = 0;
> +
> +  if (b != nullptr && b->loc->next != nullptr)
> +    {
> +      const bp_location *bl_i;
> +
> +      for (bl_i = b->loc;
> +	   bl_i != bl && bl_i->next != nullptr;
> +	   bl_i = bl_i->next)
> +	locno++;
> +
> +      if (bl_i == bl)
> +	locno++;
> +      else
> +	{
> +	  warning (_("location number not found for breakpoint %d address %s."),
> +		   b->number, paddress (bl->gdbarch, bl->address));
> +	  locno = 0;
> +	}
> +    }
> +
> +  return locno;
> +}
> +
> +/* See breakpoint.h.  */
> +
> +void
> +print_num_locno (const bpstat *bs, struct ui_out *uiout)
> +{
> +  struct breakpoint *b = bs->breakpoint_at;
> +
> +  if (b == nullptr)
> +    uiout->text (_("deleted breakpoint"));
> +  else
> +    {
> +      uiout->field_signed ("bkptno", b->number);
> +
> +      int locno = bpstat_locno (bs);
> +      if (locno != 0)
> +	uiout->message (".%pF", signed_field ("locno", locno));
> +    }
> +}
> +
>  /* See breakpoint.h.  */
>  
> 
>  void
> @@ -9176,7 +9232,7 @@ ranged_breakpoint::print_it (const bpstat *bs) const
>  		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
> @@ -11610,12 +11666,13 @@ ordinary_breakpoint::print_it (const bpstat *bs) const
>  			   async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> +
>    if (bp_temp)
> -    uiout->message ("Temporary breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Temporary breakpoint ");
>    else
> -    uiout->message ("Breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Breakpoint ");
> +  print_num_locno (bs, uiout);
> +  uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
>  }
> @@ -13220,9 +13277,13 @@ enable_disable_command (const char *args, int from_tty, bool enable)
>  	  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)
> +	      && (bp_loc_range.first == 0
> +		  || (bp_loc_range.first == 1
> +		      && bp_num_range.first == bp_num_range.second
> +		      && !has_multiple_locations (bp_num_range.first))))
>  	    {
> -	      /* Handle breakpoint ids with formats 'x' or 'x-z'.  */
> +	      /* Handle breakpoint ids with formats 'x' or 'x-z'
> +		 or 'y.1' where y has only one code location.  */
>  	      map_breakpoint_number_range (bp_num_range,
>  					   enable
>  					   ? enable_breakpoint
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 566f1285e46..96d61ef5427 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -1231,6 +1231,20 @@ extern enum print_stop_action bpstat_print (bpstat *, int);
>     Return 1 otherwise.  */
>  extern int bpstat_num (bpstat **, int *);
>  
> 
> +/* If BS indicates a breakpoint and this breakpoint has several code locations,
> +   return the location number of BS, otherwise return 0.  */
> +
> +extern int bpstat_locno (const bpstat *bs);
> +
> +/* Print BS breakpoint number optionally followed by a . and breakpoint locno.
> +
> +   For a breakpoint with only one code location, outputs the signed field
> +   "bkptno" breakpoint number of BS (as returned by bpstat_num).
> +   If BS has several code locations, outputs a '.' character followed by
> +   the signed field "locno" (as returned by bpstat_locno).  */
> +
> +extern void print_num_locno (const bpstat *bs, struct ui_out *);
> +
>  /* Perform actions associated with the stopped inferior.  Actually, we
>     just use this for breakpoint commands.  Perhaps other actions will
>     go here later, but this is executed at a late time (from the
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 434add3a663..391b81f8863 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -4338,9 +4338,65 @@ are operated on.
>  @cindex latest breakpoint
>  Breakpoints are set with the @code{break} command (abbreviated
>  @code{b}).  The debugger convenience variable @samp{$bpnum} records the
> -number of the breakpoint you've set most recently; see @ref{Convenience
> -Vars,, Convenience Variables}, for a discussion of what you can do with
> -convenience variables.
> +number of the breakpoint you've set most recently:
> +@smallexample
> +(gdb) b main
> +Breakpoint 1 at 0x11c6: file zeoes.c, line 24.
> +(gdb) p $bpnum
> +$1 = 1
> +@end smallexample
> +
> +A breakpoint may be mapped to multiple code locations for example with
> +inlined functions, Ada generics, C@t{++} templates or overloaded function names.
> +@value{GDBN} then indicates the number of code locations in the breakpoint
> +command output:
> +@smallexample
> +(gdb) b some_func
> +Breakpoint 2 at 0x1179: some_func. (3 locations)
> +(gdb) p $bpnum
> +$2 = 2
> +(gdb)
> +@end smallexample
> +
> +@vindex $bkptno@r{, convenience variable}
> +@vindex $locno@r{, convenience variable}
> +When your program stops on a breakpoint, the convenience variables
> +@samp{$bkptno} and @samp{$locno} are respectively set to the number of
> +the encountered breakpoint and the number of the breakpoint's code location:
> +@smallexample
> +Thread 1 "zeoes" hit Breakpoint 2.1, some_func () at zeoes.c:8
> +8	  printf("some func\n");
> +(gdb) p $bkptno
> +$5 = 2
> +(gdb) p $locno
> +$6 = 1
> +(gdb)
> +@end smallexample
> +
> +Note that @samp{$bkptno} and @samp{$bpnum} are not equivalent:
> +@samp{$bkptno} is set to the breakpoint number @b{last hit}, while
> +@samp{$bpnum} is set to the breakpoint number @b{last set}.
> +
> +
> +If the encountered breakpoint has only one code location, @samp{$locno} is set
> +to 1:
> +@smallexample
> +Breakpoint 1, main (argc=1, argv=0x7fffffffe018) at zeoes.c:24
> +24	  if (argc > 1)
> +(gdb) p $bkptno
> +$3 = 1
> +(gdb) p $locno
> +$4 = 1
> +(gdb)
> +@end smallexample
> +
> +The @samp{$bkptno} and @samp{$locno} variables can typically be used
> +in a breakpoint command list.
> +(@pxref{Break Commands, ,Breakpoint Command Lists}). For example, as
> +part of the breakpoint command list, you can disable completely the
> +encountered breakpoint using @samp{disable $bkptno} or disable the
> +specific encountered breakpoint location using @samp{disable
> +$bkptno.$locno}.
>  
> 
>  @table @code
>  @item break @var{locspec}
> @@ -5739,6 +5795,13 @@ Expressions}).
>  Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
>  disabled within a @var{command-list}.
>  
> 
> +Inside a command list, you can use the command
> +@kbd{disable $bkptno} to disable the encountered breakpoint.
> +
> +If your breakpoint has several code locations, the command
> +@kbd{disable $bkptno.$locno} will disable the specific breakpoint code
> +location encountered.
> +
>  You can use breakpoint commands to start your program up again.  Simply
>  use the @code{continue} command, or @code{step}, or any other command
>  that resumes execution.
> @@ -32570,6 +32633,20 @@ line="13",arch="i386:x86_64"@}
>  (gdb)
>  @end smallexample
>  
> 
> +For a @samp{breakpoint-hit} stopped reason, when the breakpoint
> +encountered has multiple locations, the field @samp{bkptno} is
> +followed by the field @samp{locno}.
> +
> +@smallexample
> +-exec-continue
> +^running
> +(gdb)
> +@@Hello world
> +*stopped,reason="breakpoint-hit",disp="keep",bkptno="2",locno="3",frame=@{
> +func="foo",args=[],file="hello.c",fullname="/home/foo/bar/hello.c",
> +line="13",arch="i386:x86_64"@}
> +(gdb)
> +@end smallexample
>  
> 
>  @subheading The @code{-exec-finish} Command
>  @findex -exec-finish
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 02c98b50c8c..e5ad062a914 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -8494,7 +8494,21 @@ print_stop_location (const target_waitstatus &ws)
>       LOCATION: Print only location
>       SRC_AND_LOC: Print location and source line.  */
>    if (do_frame_printing)
> -    print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    {
> +      if (tp->control.stop_bpstat != nullptr)
> +	{
> +	  const struct breakpoint *b = tp->control.stop_bpstat->breakpoint_at;
> +
> +	  if (b != nullptr)
> +	    {
> +	      int locno = bpstat_locno (tp->control.stop_bpstat);
> +	      set_internalvar_integer (lookup_internalvar ("bkptno"), b->number);
> +	      set_internalvar_integer (lookup_internalvar ("locno"),
> +				       (locno > 0 ? locno : 1));
> +	    }
> +	}
> +      print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    }
>  }
>  
> 
>  /* See infrun.h.  */
> diff --git a/gdb/testsuite/gdb.ada/bp_inlined_func.exp b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> index 076e8c2425f..3f94c163819 100644
> --- a/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> +++ b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> @@ -42,7 +42,7 @@ gdb_test "break read_small" \
>  for {set i 0} {$i < 4} {incr i} {
>      with_test_prefix "iteration $i" {
>  	gdb_test "continue" \
> -	    "Breakpoint $decimal, b\\.read_small \\(\\).*" \
> +	    "Breakpoint $bkptno_num_re, b\\.read_small \\(\\).*" \
>  	    "stopped in read_small"
>      }
>  }
> diff --git a/gdb/testsuite/gdb.ada/operator_bp.exp b/gdb/testsuite/gdb.ada/operator_bp.exp
> index 655e7af479f..e3928419ed6 100644
> --- a/gdb/testsuite/gdb.ada/operator_bp.exp
> +++ b/gdb/testsuite/gdb.ada/operator_bp.exp
> @@ -56,7 +56,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to \"$op\""
>  }
>  
> 
> @@ -86,7 +86,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to ops.\"$op\""
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> index b540df973a3..742315178e3 100644
> --- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> +++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> @@ -140,11 +140,11 @@ with_test_prefix "scenario 1" {
>      gdb_run_cmd
>  
> 
>      # Check our conditional breakpoints.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> @@ -208,11 +208,11 @@ with_test_prefix "scenario 2" {
>      gdb_run_cmd
>  
> 
>      # Check that we hit enabled locations only.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> diff --git a/gdb/testsuite/gdb.base/ctxobj.exp b/gdb/testsuite/gdb.base/ctxobj.exp
> index 9c010f54d79..0b589a7d6e6 100644
> --- a/gdb/testsuite/gdb.base/ctxobj.exp
> +++ b/gdb/testsuite/gdb.base/ctxobj.exp
> @@ -67,9 +67,16 @@ gdb_test "break ctxobj-f.c:$bp_location" \
>           "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
>           "break in get_version functions"
>  
> 
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_1 \\(\\).*" \
> -         "continue to get_version_1"
> +global expect_out
> +set test "continue to get_version_1"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_1 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  # Try printing "this_version_num".  There are two global variables
>  # with that name, and some systems such as GNU/Linux merge them
> @@ -100,10 +107,15 @@ gdb_test "print this_version_num == v" \
>          "print libctxobj1's this_version_num from symtab"
>  
> 
>  # Do the same, but from get_version_2.
> -
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_2 \\(\\).*" \
> -         "continue to get_version_2"
> +set test "continue to get_version_2"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_2 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  gdb_test "print this_version_num == v" \
>           " = 1" \
> diff --git a/gdb/testsuite/gdb.base/ena-dis-br.exp b/gdb/testsuite/gdb.base/ena-dis-br.exp
> index 24925cf7185..04b3f134b44 100644
> --- a/gdb/testsuite/gdb.base/ena-dis-br.exp
> +++ b/gdb/testsuite/gdb.base/ena-dis-br.exp
> @@ -67,14 +67,21 @@ gdb_test "info break $bp" \
>  # See the comments in condbreak.exp for "run until breakpoint at
>  # marker1" for an explanation of the xfail below.
>  set test "continue to break marker1"
> +set bpno 0
>  gdb_test_multiple "continue" "$test" {
> -    -re "Breakpoint \[0-9\]*, marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	pass "$test"
>      }
> -    -re "Breakpoint \[0-9\]*, $hex in marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), $hex in marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	xfail "$test"
>      }
>  }
> +# Verify the $bkptno convenience variable is equal to the hit bpno.
> +gdb_test "print \$bkptno" " = $bpno" "$test \$bkptno is $bpno"
> +# Verify the $locno is 1, as there is only one code location.
> +gdb_test "print \$locno" " = 1" "$test \$locno is 1"
>  
> 
>  gdb_test_no_output "delete $bp" "delete break marker1"
>  
> 
> @@ -359,7 +366,8 @@ with_test_prefix "4th breakpoint" {
>  }
>  
> 
>  # Perform tests for disable/enable commands on multiple
> -# locations and breakpoints.
> +# code locations and breakpoints.  If a breakpoint has only one code location,
> +# enable/disable num  and enable/disable num.1 should be equivalent.
>  #
>  # WHAT - the command to test (disable/enable).
>  #
> @@ -372,7 +380,7 @@ proc test_ena_dis_br { what } {
>      global b3
>      global b4
>      global gdb_prompt
> -    
> +
>      # OPPOS    - the command opposite to WHAT.
>      # WHAT_RES - whether breakpoints are expected to end
>      #            up enabled or disabled.
> @@ -395,13 +403,13 @@ proc test_ena_dis_br { what } {
>  	set p2 "pass"
>      }
>  
> 
> -    # Now enable(disable) $b.1 $b2.1.
> +    # Now enable(disable) $b1.1 $b2.1.
>      gdb_test_no_output "$what $b1.1 $b2.1" "$what \$b1.1 \$b2.1"
>      set test1 "${what}d \$b1.1 and \$b2.1"
>  
> 
>      # Now $b1.1 and $b2.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -       -re "(${b1}.1)(\[^\n\r\]*)( n.*)(${b2}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +       -re "(${b1})(\[^\n\r\]*)( n.*)(${b2})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> @@ -420,19 +428,16 @@ proc test_ena_dis_br { what } {
>         "${what}d \$b1"
>  
> 
>      gdb_test_no_output "$oppos $b3" "$oppos \$b3"
> +    # Now $b4 $b3 should be enabled(disabled)
> +    set test1 "${what}d \$b4 and \$b3"
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $oppos_res.*).*(${b4})(\[^\n\r\]*)( $oppos_res.*)" "$test1"
> +
>      gdb_test_no_output "$what $b4 $b3.1" "$what \$b4 \$b3.1"
> -    set test1 "${what}d \$b4 and \$b3.1,remain ${oppos}d \$b3"
> +    set test1 "${what}d \$b4 and \$b3.1, changing \$b3"
> +
> +    # Now $b4 $b3 should be enabled(disabled)
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $what_res.*).*(${b4})(\[^\n\r\]*)( $what_res.*)" "$test1"
>  
> 
> -    # Now $b4 $b3.1 should be enabled(disabled) and
> -    # $b3 should remain disabled(enabled).
> -    gdb_test_multiple "info break" "$test1" {
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b3}.1)(\[^\n\r\]*)( n.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p1 "$test1"
> -       }
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p2 "$test1"
> -       }
> -    }
>  
> 
>      # Now enable(disable) '$b4.1 fooobaar'.  This should error on
>      # fooobaar.
> @@ -443,7 +448,7 @@ proc test_ena_dis_br { what } {
>  
> 
>      # $b4.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -        -re "(${b4}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +        -re "(${b4})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.base/foll-exec-mode.exp b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> index 918f3e4fd5f..cb6d975a767 100644
> --- a/gdb/testsuite/gdb.base/foll-exec-mode.exp
> +++ b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> @@ -99,7 +99,7 @@ proc do_catch_exec_test { } {
>  # before re-running.
>  
> 
>  proc do_follow_exec_mode_tests { mode cmd infswitch } {
> -    global binfile srcfile srcfile2 testfile testfile2
> +    global binfile srcfile srcfile2 testfile testfile2 bkptno_numopt_re
>      global gdb_prompt
>  
> 
>      with_test_prefix "$mode,$cmd,$infswitch" {
> @@ -125,7 +125,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  	# Set up the output we expect to see after we execute past the exec.
>  	#
>  	set execd_line [gdb_get_line_number "after-exec" $srcfile2]
> -	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint .,.*${srcfile2}:${execd_line}.*$gdb_prompt $"
> +	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint ${bkptno_numopt_re},.*${srcfile2}:${execd_line}.*$gdb_prompt $"
>  
> 
>  	# Set a breakpoint after the exec call if we aren't single-stepping
>  	# past it.
> @@ -189,7 +189,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  		send_gdb "y\n"
>  		exp_continue
>  	    }
> -	    -re "Starting program: .*$expected_inf.*Breakpoint .,.*\r\n$gdb_prompt $" {
> +	    -re "Starting program: .*$expected_inf.*Breakpoint $bkptno_numopt_re,.*\r\n$gdb_prompt $" {
>  		pass $test
>  	    }
>  	}
> diff --git a/gdb/testsuite/gdb.base/pie-fork.exp b/gdb/testsuite/gdb.base/pie-fork.exp
> index efc357d39a2..19e9d3a5537 100644
> --- a/gdb/testsuite/gdb.base/pie-fork.exp
> +++ b/gdb/testsuite/gdb.base/pie-fork.exp
> @@ -54,10 +54,10 @@ proc_with_prefix test_detach_on_fork_follow_child {} {
>  proc_with_prefix test_no_detach_on_fork {} {
>      setup_test "off"
>  
> 
> -    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2.1, break_here.*" \
>  	     "continue from thread 1.1"
>      gdb_test "thread 2.1"
> -    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2.2, break_here.*" \
>  	     "continue from thread 2.1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/step-over-exit.exp b/gdb/testsuite/gdb.base/step-over-exit.exp
> index f8bd99980fe..575319c564c 100644
> --- a/gdb/testsuite/gdb.base/step-over-exit.exp
> +++ b/gdb/testsuite/gdb.base/step-over-exit.exp
> @@ -91,7 +91,7 @@ delete_breakpoints
>  
> 
>  gdb_test "break marker"
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_num_re, .*" \
>      "continue to marker, first time"
>  
> 
>  # Step 2, create a breakpoint which evaluates false, and force it
> @@ -120,5 +120,5 @@ gdb_test "inferior 1" ".*Switching to inferior 1.*" \
>  # Switch back to the parent process, continue to the marker to
>  # test GDBserver's state is still correct.
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_numopt_re, .*" \
>      "continue to marker, second time"
> diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
> index 47a2a5dcb7c..fa098602c31 100644
> --- a/gdb/testsuite/gdb.cp/mb-inline.exp
> +++ b/gdb/testsuite/gdb.cp/mb-inline.exp
> @@ -46,7 +46,7 @@ gdb_test "info break" \
>      "\[\r\n\]1\.1.* y .* at .*$hdrfile:$bp_location.*\[\r\n\]1\.2.* y .* at .*$hdrfile:$bp_location.*"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo \\(i=1\\).*" \
> @@ -59,7 +59,7 @@ gdb_test "continue" \
>  gdb_test_no_output "disable 1.2" "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
>  
> 
>  gdb_test_multiple "info break" "disabled breakpoint 1.2" {
>      -re "1\.2.* n .* at .*$hdrfile:$bp_location.*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
> index 6c988e7335e..0c0d46fcb7a 100644
> --- a/gdb/testsuite/gdb.cp/mb-templates.exp
> +++ b/gdb/testsuite/gdb.cp/mb-templates.exp
> @@ -42,7 +42,7 @@ gdb_run_cmd
>  
> 
>  set test "initial condition: run to breakpoint"
>  gdb_test_multiple "" $test {
> -    -re "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
> +    -re "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
>  	pass $test
>  	break
>      }
> @@ -67,7 +67,7 @@ gdb_test_no_output {condition $bpnum i==1} \
>      "separate condition: set condition"
>      
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo<double> \\(i=1\\).*" \
> @@ -79,7 +79,7 @@ gdb_test "continue" \
>  gdb_test_no_output {disable $bpnum.1} "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
>  
> 
>  # Try disabling entire breakpoint
>  gdb_test_no_output {enable $bpnum.1} "disabling location: enable"
> diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
> index 06adf82ecbb..0ed9eae055b 100644
> --- a/gdb/testsuite/gdb.cp/ovldbreak.exp
> +++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
> @@ -380,7 +380,7 @@ gdb_test "info break" $bptable "breakpoint info (after setting on all)"
>  
> 
>  # Run through each breakpoint.
>  proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
> -    global gdb_prompt hex decimal srcfile
> +    global gdb_prompt hex decimal srcfile bkptno_num_re
>  
> 
>      if {$argument == ""} {
>          set actuals ""
> @@ -398,11 +398,11 @@ proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
>      }
>  
> 
>      gdb_test_multiple "continue" "continue to bp overloaded : $argtype" {
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              pass "continue to bp overloaded : $argtype"
>          }
>  
> 
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              if $might_kfail {
>                  kfail "c++/8130" "continue to bp overloaded : $argtype"
>              } else {
> diff --git a/gdb/testsuite/gdb.gdb/python-helper.exp b/gdb/testsuite/gdb.gdb/python-helper.exp
> index 6db8bf0df50..30eb6038f3a 100644
> --- a/gdb/testsuite/gdb.gdb/python-helper.exp
> +++ b/gdb/testsuite/gdb.gdb/python-helper.exp
> @@ -49,7 +49,7 @@ gdb_exit
>  # The main test.  This is called by the self-test framework once GDB
>  # has been started on a copy of itself.
>  proc test_python_helper {} {
> -    global py_helper_script decimal hex gdb_prompt
> +    global py_helper_script decimal hex gdb_prompt bkptno_numopt_re
>      global inferior_spawn_id
>  
> 
>      # Source the python helper script.  This script registers the
> @@ -233,7 +233,7 @@ proc test_python_helper {} {
>      # GDB stopping at the value_print breakpoint again.
>      send_inferior "ptype global_c\n"
>      gdb_test_multiple "" "hit breakpoint in outer gdb again" {
> -	-re "Breakpoint $decimal, c_print_type .*\\(outer-gdb\\) $" {
> +	-re "Breakpoint $bkptno_numopt_re, c_print_type .*\\(outer-gdb\\) $" {
>  	    pass $gdb_test_name
>  	}
>      }
> diff --git a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> index 19ccbe85e04..c080955049c 100644
> --- a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> +++ b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> @@ -69,7 +69,7 @@ if { $use_second_inferior } {
>  	"\\^running.*" \
>  	"run inferior 2"
>  
> 
> -    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\""} \
> +    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\"" "locno=\"[0-9]+\""} \
>  	"inferior i2 stops at all_threads_started"
>  
> 
>      mi_send_resuming_command "exec-continue --thread-group i2" \
> diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> index d78c96ddef1..9eec083068b 100644
> --- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> +++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> @@ -307,8 +307,13 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  	    # Consume MI event output.
>  	    with_spawn_id $mi_spawn_id {
> -		mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> -		    "$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		if { $inf == 1 } {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		} else {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} "stop at breakpoint in main"
> +		}
>  	    }
>  
> 
>  	    if { $mode == "all-stop" } {
> @@ -330,9 +335,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		    # Consume MI output.
>  		    with_spawn_id $mi_spawn_id {
> -			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			    "thread $inf.$thread stops MI"
> +			if { $inf == 1} {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +				"thread $inf.$thread stops MI"
> +			} else {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +				"thread $inf.$thread stops MI"
> +			}
>  		    }
>  		}
>  
> 
> @@ -359,9 +370,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		# Consume MI output.
>  		with_spawn_id $mi_spawn_id {
> -		    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			"thread $inf.2 stops MI"
> +		    if { $inf == 1} {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +			    "thread $inf.2 stops MI"
> +		    } else {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +			    "thread $inf.2 stops MI"
> +		    }
>  		}
>  	    }
>  	}
> @@ -434,7 +451,7 @@ proc_with_prefix test_setup { mode } {
>  
> 
>  	with_spawn_id $mi_spawn_id {
>  	    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" "$decimal" \
> -		{"" "disp=\"del\""} "main stop"
> +		{"" "disp=\"del\"" "locno=\"[0-9]+\""} "main stop"
>  	}
>  
> 
>  	# Consume CLI output.
> diff --git a/gdb/testsuite/gdb.multi/multi-arch-exec.exp b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> index a1496fb5571..dfdb746c65e 100644
> --- a/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> +++ b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> @@ -148,6 +148,7 @@ proc build_executables { first_arch } {
>  }
>  
> 
>  proc do_test { first_arch mode selected_thread } {
> +        global bkptno_numopt_re
>  	set from_exec "$first_arch-multi-arch-exec"
>  
> 
>  	clean_restart ${from_exec}
> @@ -169,7 +170,7 @@ proc do_test { first_arch mode selected_thread } {
>  
> 
>  	# Test that GDB updates the target description / arch successfuly
>  	# after the exec.
> -	gdb_test "continue" "Breakpoint 2, main.*" "continue across exec that changes architecture"
> +	gdb_test "continue" "Breakpoint $bkptno_numopt_re, main.*" "continue across exec that changes architecture"
>  }
>  
> 
>  # Test both arch1=>arch2 and arch2=>arch1.
> diff --git a/gdb/testsuite/gdb.multi/run-only-second-inf.exp b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> index fec2575f904..b94689d0bfa 100644
> --- a/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> +++ b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> @@ -46,5 +46,5 @@ gdb_load $binfile
>  if {[gdb_start_cmd] < 0} {
>      fail "start the second inf"
>  } else {
> -    gdb_test "" ".*reakpoint ., main .*${srcfile}.*" "start the second inf"
> +    gdb_test "" ".*reakpoint $bkptno_numopt_re, main .*${srcfile}.*" "start the second inf"
>  }
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> index cbccba19d12..3c079facced 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> @@ -27,7 +27,7 @@ if {[build_executable "failed to build" $testfile $srcfile {debug}]} {
>  # child.  Can be either "kill", "detach", or "exit" (to continue it to
>  # normal exit).
>  proc do_test {dispose} {
> -    global binfile
> +    global binfile bkptno_numopt_re
>  
> 
>      clean_restart $binfile
>  
> 
> @@ -77,7 +77,7 @@ proc do_test {dispose} {
>      #  Command aborted.
>      #  (gdb)
>      #
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker .*" \
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker .*" \
>  	"continue in inferior 1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi.exp b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> index e4329dca6c2..0fc1bee762f 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> @@ -84,11 +84,11 @@ if [skip_hw_watchpoint_multi_tests] {
>  	"Hardware access \\(read/write\\) watchpoint \[0-9\]+: c\r\n\r\nOld value = 0\r\nNew value = 3\r\n.*" \
>  	"catch c on inferior 2"
>  
> 
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 2"
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 2"
>  
> 
>      gdb_test "inferior 1" "witching to inferior 1 .*" "switch back to inferior 1 again"
>  
> 
>      gdb_test "continue" "Hardware access \\(read/write\\) watchpoint \[0-9\]+: b\r\n\r\nOld value = 0\r\nNew value = 2\r\n.*" "catch b on inferior 1"
>  }
>  
> 
> -gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 1"
> +gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 1"
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 402450152ac..5e4c793598e 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -227,6 +227,14 @@ set inferior_exited_re "(?:\\\[Inferior \[0-9\]+ \\(\[^\n\r\]*\\) exited)"
>  # E.g., $1, $2, etc.
>  set valnum_re "\\\$$decimal"
>  
> 
> +# A regular expression that matches a breakpoint hit with a breakpoint
> +# having several code locations.
> +set bkptno_num_re "$decimal\\.$decimal"
> +
> +# A regular expression that matches a breakpoint hit
> +# with one or several code locations.
> +set bkptno_numopt_re "($decimal\\.$decimal|$decimal)"
> +
>  ### Only procedures should come after this point.
>  
> 
>  #
> @@ -662,6 +670,7 @@ proc gdb_breakpoint { linespec args } {
>  
> 
>  proc runto { linespec args } {
>      global gdb_prompt
> +    global bkptno_numopt_re
>      global decimal
>  
> 
>      delete_breakpoints
> @@ -699,7 +708,7 @@ proc runto { linespec args } {
>  	    }
>  	    return 1
>  	}
> -	-re "Breakpoint \[0-9\]*, \[0-9xa-f\]* in .*$gdb_prompt $" { 
> +	-re "Breakpoint $bkptno_numopt_re, \[0-9xa-f\]* in .*$gdb_prompt $" {
>  	    if { $print_pass } {
>  		pass $test_name
>  	    }
> diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
> index e578a7e6f9b..ea66fdcabf8 100644
> --- a/gdb/testsuite/lib/mi-support.exp
> +++ b/gdb/testsuite/lib/mi-support.exp
> @@ -1195,11 +1195,11 @@ proc mi_detect_async {} {
>  # filename of a file without debug info.  ARGS should not include [] the
>  # list of argument is enclosed in, and other regular expressions should
>  # not include quotes.
> -# If EXTRA is a list of one element, it's the regular expression
> +# EXTRA can be a list of one, two or three elements.
> +# The first element is the regular expression
>  # for output expected right after *stopped, and before GDB prompt.
> -# If EXTRA is a list of two elements, the first element is for
> -# output right after *stopped, and the second element is output
> -# right after reason field.  The regex after reason should not include
> +# The third element is the regulation expression for the locno
> +# right after bkptno field.  The locno regex should not include
>  # the comma separating it from the following fields.
>  #
>  # When we fail to match output at all, -1 is returned.  If FILE does
> @@ -1224,7 +1224,14 @@ proc mi_expect_stop { reason func args file line extra test } {
>  
> 
>      set after_stopped ""
>      set after_reason ""
> -    if { [llength $extra] == 2 } {
> +    set locno ""
> +    if { [llength $extra] == 3 } {
> +	set after_stopped [lindex $extra 0]
> +	set after_reason [lindex $extra 1]
> +	set after_reason "${after_reason},"
> +	set locno [lindex $extra 2]
> +	set locno "${locno},"
> +    } elseif { [llength $extra] == 2 } {
>  	set after_stopped [lindex $extra 0]
>  	set after_reason [lindex $extra 1]
>  	set after_reason "${after_reason},"
> @@ -1298,10 +1305,12 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set ebn ""
>      if { $reason == "breakpoint-hit" } {
>  	set bn {bkptno="[0-9]+",}
> +	set bn "${bn}${locno}"
>      } elseif { $reason == "solib-event" } {
>  	set bn ".*"
>      } elseif { $reason == "exception-caught" } {
>  	set ebn {bkptno="[0-9]+",}
> +	set ebn "${ebn}${locno}"
>  	set bn ".*"
>  	set reason "breakpoint-hit"
>      }
> @@ -1315,6 +1324,7 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set a $after_reason
>  
> 
>      verbose -log "mi_expect_stop: expecting: \\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
> +
>      gdb_expect {
>  	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
>  	    pass "$test"



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-06-13 17:51 ` Philippe Waroquiers
@ 2022-06-14 17:32   ` Keith Seitz
  2022-06-14 17:41     ` Eli Zaretskii
  0 siblings, 1 reply; 17+ messages in thread
From: Keith Seitz @ 2022-06-14 17:32 UTC (permalink / raw)
  To: Philippe Waroquiers, gdb-patches

On 6/13/22 10:51, Philippe Waroquiers via Gdb-patches wrote:
> Ping ?
> 

FWIW, thank you for your comments and revision regarding my comments.

I cannot approve your patch, but I hope someone will. This feature is
long overdue.

Keith


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-06-14 17:32   ` Keith Seitz
@ 2022-06-14 17:41     ` Eli Zaretskii
  2022-06-14 21:27       ` Philippe Waroquiers
  0 siblings, 1 reply; 17+ messages in thread
From: Eli Zaretskii @ 2022-06-14 17:41 UTC (permalink / raw)
  To: Keith Seitz; +Cc: philippe.waroquiers, gdb-patches

> Date: Tue, 14 Jun 2022 10:32:22 -0700
> X-Spam-Status: No, score=-6.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH,
>  DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, NICE_REPLY_A,
>  RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP,
>  T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6
> From: Keith Seitz via Gdb-patches <gdb-patches@sourceware.org>
> 
> On 6/13/22 10:51, Philippe Waroquiers via Gdb-patches wrote:
> > Ping ?
> > 
> 
> FWIW, thank you for your comments and revision regarding my comments.
> 
> I cannot approve your patch, but I hope someone will. This feature is
> long overdue.

The documentation parts were approved, right?

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-06-14 17:41     ` Eli Zaretskii
@ 2022-06-14 21:27       ` Philippe Waroquiers
  0 siblings, 0 replies; 17+ messages in thread
From: Philippe Waroquiers @ 2022-06-14 21:27 UTC (permalink / raw)
  To: Eli Zaretskii, Keith Seitz; +Cc: gdb-patches

On Tue, 2022-06-14 at 20:41 +0300, Eli Zaretskii wrote:
> > Date: Tue, 14 Jun 2022 10:32:22 -0700
> > X-Spam-Status: No, score=-6.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH,
> >  DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, NICE_REPLY_A,
> >  RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP,
> >  T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6
> > From: Keith Seitz via Gdb-patches <gdb-patches@sourceware.org>
> > 
> > On 6/13/22 10:51, Philippe Waroquiers via Gdb-patches wrote:
> > > Ping ?
> > > 
> > 
> > FWIW, thank you for your comments and revision regarding my comments.
> > 
> > I cannot approve your patch, but I hope someone will. This feature is
> > long overdue.
> 
> The documentation parts were approved, right?
Yes, there were two small nits to fix, which I did.
Thanks again for the review.

Philippe



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-06-06  9:45 [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno Philippe Waroquiers
  2022-06-06 10:53 ` Eli Zaretskii
  2022-06-13 17:51 ` Philippe Waroquiers
@ 2022-06-19 17:46 ` Philippe Waroquiers
  2022-06-26 17:27 ` Philippe Waroquiers
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Philippe Waroquiers @ 2022-06-19 17:46 UTC (permalink / raw)
  To: gdb-patches

Ping ^ 2
(Eli reviewed the doc, Keith did a first review)

Thanks
Philippe


On Mon, 2022-06-06 at 11:45 +0200, Philippe Waroquiers wrote:
> Before this patch, when a breakpoint that has multiple locations is reached,
> GDB printed:
>   Thread 1 "zeoes" hit Breakpoint 1, some_func () at somefunc1.c:5
> 
> This patch changes the message so that bkpt_print_id prints the precise
> encountered breakpoint:
>   Thread 1 "zeoes" hit Breakpoint 1.2, some_func () at somefunc1.c:5
> 
> In mi mode, bkpt_print_id also (optionally) prints a new table field "locno":
>   locno is printed when the breakpoint has more than one location.
> Note that according to the GDB user manual node 'GDB/MI Development and Front
> Ends', it is ok to add new fields without changing the MI version.
> 
> Also, when a breakpoint is reached, the convenience variables
> $bkptno and $locno are set to the encountered breakpoint number
> and location number.
> 
> $bkptno and $locno can a.o. be used in the command list of a breakpoint,
> to disable the specific encountered breakpoint, e.g.
>    disable $bkptno.$locno
> 
> In case the breakpoint has only one location, $locno is still set to
> the value 1, so as to allow a command such as:
>   disable $bkptno.$locno
> even when the breakpoint has only one location.
> 
> This also fixes a strange behaviour: when a breakpoint X has only
> one location,
>   enable|disable X.1
> is accepted but transforms the breakpoint in a multiple locations
> breakpoint having only one location.
> 
> The changes in RFA v3 handle the additional comments of Eli:
>  GDB/NEW:
>   - Use max 80-column
>   - Use 'code location' instead of 'location'.
>   - Fix typo $bkpno
>   - Ensure that disable $bkptno and disable $bkptno.$locno have
>     each their explanation inthe example
>   - Reworded the 'breakpoint-hit' paragraph.
>  gdb.texinfo:
>   - Use 'code location' instead of 'location'.
>   - Add a note to clarify the distinction between $bkptno and $bpnum.
>   - Use @kbd instead of examples with only one command.
> 
> Compared to RFA v1, the changes in v2 handle the comments given by
> Keith Seitz and Eli Zaretskii:
>   - Use %s for the result of paddress
>   - Use bkptno_numopt_re instead of 2 different -re cases
>   - use C@t{++}
>   - Add index entries for $bkptno and $locno
>   - Added an example for "locno" in the mi interface
>   - Added examples in the Break command manual.
> ---
>  gdb/NEWS                                      | 21 +++++
>  gdb/ada-lang.c                                |  2 +-
>  gdb/break-catch-syscall.c                     |  2 +-
>  gdb/break-catch-throw.c                       |  2 +-
>  gdb/breakpoint.c                              | 93 +++++++++++++++----
>  gdb/breakpoint.h                              | 14 +++
>  gdb/doc/gdb.texinfo                           | 83 ++++++++++++++++-
>  gdb/infrun.c                                  | 16 +++-
>  gdb/testsuite/gdb.ada/bp_inlined_func.exp     |  2 +-
>  gdb/testsuite/gdb.ada/operator_bp.exp         |  4 +-
>  .../gdb.base/condbreak-multi-context.exp      |  8 +-
>  gdb/testsuite/gdb.base/ctxobj.exp             | 26 ++++--
>  gdb/testsuite/gdb.base/ena-dis-br.exp         | 41 ++++----
>  gdb/testsuite/gdb.base/foll-exec-mode.exp     |  6 +-
>  gdb/testsuite/gdb.base/pie-fork.exp           |  4 +-
>  gdb/testsuite/gdb.base/step-over-exit.exp     |  4 +-
>  gdb/testsuite/gdb.cp/mb-inline.exp            |  4 +-
>  gdb/testsuite/gdb.cp/mb-templates.exp         |  6 +-
>  gdb/testsuite/gdb.cp/ovldbreak.exp            |  6 +-
>  gdb/testsuite/gdb.gdb/python-helper.exp       |  4 +-
>  .../gdb.mi/interrupt-thread-group.exp         |  2 +-
>  .../gdb.mi/user-selected-context-sync.exp     | 35 +++++--
>  gdb/testsuite/gdb.multi/multi-arch-exec.exp   |  3 +-
>  .../gdb.multi/run-only-second-inf.exp         |  2 +-
>  .../gdb.multi/watchpoint-multi-exit.exp       |  4 +-
>  gdb/testsuite/gdb.multi/watchpoint-multi.exp  |  4 +-
>  gdb/testsuite/lib/gdb.exp                     | 11 ++-
>  gdb/testsuite/lib/mi-support.exp              | 20 +++-
>  28 files changed, 335 insertions(+), 94 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 960f90b4387..a5602deee2b 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -34,6 +34,21 @@
>       whitespace from each line before using the string as the help
>       output.
>  
> 
> +* When a breakpoint with multiple code locations is hit, GDB now prints
> +  the code location using the syntax <breakpoint_number>.<location_number>
> +  such as in:
> +     Thread 1 "zeoes" hit Breakpoint 2.3, some_func () at zeoes.c:8
> +
> +* When a breakpoint is hit, GDB now sets the convenience variables $bkptno and
> +  $locno to the hit breakpoint number and code location number.
> +  This allows to disable the last hit breakpoint using
> +     (gdb) disable $bkptno
> +   or disable only the specific breakpoint code location using
> +     (gdb) disable $bkptno.$locno
> +  These commands can be used inside the command list of a breakpoint to
> +  automatically disable the just encountered breakpoint (or the just
> +  encountered specific breakpoint code location).
> +
>  * New commands
>  
> 
>  maintenance set ignore-prologue-end-flag on|off
> @@ -50,6 +65,12 @@ maintenance info line-table
>    entry corresponds to an address where a breakpoint should be placed
>    to be at the first instruction past a function's prologue.
>  
> 
> +* MI changes
> +
> + ** The async record stating the stopped reason 'breakpoint-hit' now
> +    contains an optional field locno giving the code location number
> +    when the breakpoint has multiple code locations.
> +
>  * Python API
>  
> 
>    ** New function gdb.format_address(ADDRESS, PROGSPACE, ARCHITECTURE),
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 6ab01fd27d4..bbae76f39ac 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -12348,7 +12348,7 @@ ada_catchpoint::print_it (const bpstat *bs) const
>  
> 
>    uiout->text (disposition == disp_del
>  	       ? "\nTemporary catchpoint " : "\nCatchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    /* ada_exception_name_addr relies on the selected frame being the
> diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
> index 06d48466de7..82229de33f7 100644
> --- a/gdb/break-catch-syscall.c
> +++ b/gdb/break-catch-syscall.c
> @@ -218,7 +218,7 @@ syscall_catchpoint::print_it (const bpstat *bs) const
>  						: EXEC_ASYNC_SYSCALL_RETURN));
>        uiout->field_string ("disp", bpdisp_text (b->disposition));
>      }
> -  uiout->field_signed ("bkptno", b->number);
> +  print_num_locno (bs, uiout);
>  
> 
>    if (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY)
>      uiout->text (" (call to syscall ");
> diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
> index 66cf80be1c5..5b6f5d9eca1 100644
> --- a/gdb/break-catch-throw.c
> +++ b/gdb/break-catch-throw.c
> @@ -257,7 +257,7 @@ exception_catchpoint::print_it (const bpstat *bs) const
>    bp_temp = disposition == disp_del;
>    uiout->text (bp_temp ? "Temporary catchpoint "
>  		       : "Catchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text ((kind == EX_EVENT_THROW ? " (exception thrown), "
>  		: (kind == EX_EVENT_CATCH ? " (exception caught), "
>  		   : " (exception rethrown), ")));
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index ed932a19ed7..c89c800f32f 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -820,6 +820,19 @@ get_breakpoint (int num)
>    return nullptr;
>  }
>  
> 
> +/* Return TRUE if NUM refer to an existing breakpoint that has
> +   multiple code locations.  */
> +
> +static bool
> +has_multiple_locations (int num)
> +{
> +  for (breakpoint *b : all_breakpoints ())
> +    if (b->number == num)
> +      return b->loc != nullptr && b->loc->next != nullptr;
> +
> +  return false;
> +}
> +
>  \f
>  
> 
>  /* Mark locations as "conditions have changed" in case the target supports
> @@ -4451,15 +4464,7 @@ bpstat_explains_signal (bpstat *bsp, enum gdb_signal sig)
>    return false;
>  }
>  
> 
> -/* Put in *NUM the breakpoint number of the first breakpoint we are
> -   stopped at.  *BSP upon return is a bpstat which points to the
> -   remaining breakpoints stopped at (but which is not guaranteed to be
> -   good for anything but further calls to bpstat_num).
> -
> -   Return 0 if passed a bpstat which does not indicate any breakpoints.
> -   Return -1 if stopped at a breakpoint that has been deleted since
> -   we set it.
> -   Return 1 otherwise.  */
> +/* See breakpoint.h.  */
>  
> 
>  int
>  bpstat_num (bpstat **bsp, int *num)
> @@ -4481,6 +4486,57 @@ bpstat_num (bpstat **bsp, int *num)
>    return 1;
>  }
>  
> 
> +/* See breakpoint.h  */
> +
> +int
> +bpstat_locno (const bpstat *bs)
> +{
> +  const struct breakpoint *b = bs->breakpoint_at;
> +  const struct bp_location *bl = bs->bp_location_at.get ();
> +
> +  int locno = 0;
> +
> +  if (b != nullptr && b->loc->next != nullptr)
> +    {
> +      const bp_location *bl_i;
> +
> +      for (bl_i = b->loc;
> +	   bl_i != bl && bl_i->next != nullptr;
> +	   bl_i = bl_i->next)
> +	locno++;
> +
> +      if (bl_i == bl)
> +	locno++;
> +      else
> +	{
> +	  warning (_("location number not found for breakpoint %d address %s."),
> +		   b->number, paddress (bl->gdbarch, bl->address));
> +	  locno = 0;
> +	}
> +    }
> +
> +  return locno;
> +}
> +
> +/* See breakpoint.h.  */
> +
> +void
> +print_num_locno (const bpstat *bs, struct ui_out *uiout)
> +{
> +  struct breakpoint *b = bs->breakpoint_at;
> +
> +  if (b == nullptr)
> +    uiout->text (_("deleted breakpoint"));
> +  else
> +    {
> +      uiout->field_signed ("bkptno", b->number);
> +
> +      int locno = bpstat_locno (bs);
> +      if (locno != 0)
> +	uiout->message (".%pF", signed_field ("locno", locno));
> +    }
> +}
> +
>  /* See breakpoint.h.  */
>  
> 
>  void
> @@ -9176,7 +9232,7 @@ ranged_breakpoint::print_it (const bpstat *bs) const
>  		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
> @@ -11610,12 +11666,13 @@ ordinary_breakpoint::print_it (const bpstat *bs) const
>  			   async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> +
>    if (bp_temp)
> -    uiout->message ("Temporary breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Temporary breakpoint ");
>    else
> -    uiout->message ("Breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Breakpoint ");
> +  print_num_locno (bs, uiout);
> +  uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
>  }
> @@ -13220,9 +13277,13 @@ enable_disable_command (const char *args, int from_tty, bool enable)
>  	  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)
> +	      && (bp_loc_range.first == 0
> +		  || (bp_loc_range.first == 1
> +		      && bp_num_range.first == bp_num_range.second
> +		      && !has_multiple_locations (bp_num_range.first))))
>  	    {
> -	      /* Handle breakpoint ids with formats 'x' or 'x-z'.  */
> +	      /* Handle breakpoint ids with formats 'x' or 'x-z'
> +		 or 'y.1' where y has only one code location.  */
>  	      map_breakpoint_number_range (bp_num_range,
>  					   enable
>  					   ? enable_breakpoint
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 566f1285e46..96d61ef5427 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -1231,6 +1231,20 @@ extern enum print_stop_action bpstat_print (bpstat *, int);
>     Return 1 otherwise.  */
>  extern int bpstat_num (bpstat **, int *);
>  
> 
> +/* If BS indicates a breakpoint and this breakpoint has several code locations,
> +   return the location number of BS, otherwise return 0.  */
> +
> +extern int bpstat_locno (const bpstat *bs);
> +
> +/* Print BS breakpoint number optionally followed by a . and breakpoint locno.
> +
> +   For a breakpoint with only one code location, outputs the signed field
> +   "bkptno" breakpoint number of BS (as returned by bpstat_num).
> +   If BS has several code locations, outputs a '.' character followed by
> +   the signed field "locno" (as returned by bpstat_locno).  */
> +
> +extern void print_num_locno (const bpstat *bs, struct ui_out *);
> +
>  /* Perform actions associated with the stopped inferior.  Actually, we
>     just use this for breakpoint commands.  Perhaps other actions will
>     go here later, but this is executed at a late time (from the
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 434add3a663..391b81f8863 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -4338,9 +4338,65 @@ are operated on.
>  @cindex latest breakpoint
>  Breakpoints are set with the @code{break} command (abbreviated
>  @code{b}).  The debugger convenience variable @samp{$bpnum} records the
> -number of the breakpoint you've set most recently; see @ref{Convenience
> -Vars,, Convenience Variables}, for a discussion of what you can do with
> -convenience variables.
> +number of the breakpoint you've set most recently:
> +@smallexample
> +(gdb) b main
> +Breakpoint 1 at 0x11c6: file zeoes.c, line 24.
> +(gdb) p $bpnum
> +$1 = 1
> +@end smallexample
> +
> +A breakpoint may be mapped to multiple code locations for example with
> +inlined functions, Ada generics, C@t{++} templates or overloaded function names.
> +@value{GDBN} then indicates the number of code locations in the breakpoint
> +command output:
> +@smallexample
> +(gdb) b some_func
> +Breakpoint 2 at 0x1179: some_func. (3 locations)
> +(gdb) p $bpnum
> +$2 = 2
> +(gdb)
> +@end smallexample
> +
> +@vindex $bkptno@r{, convenience variable}
> +@vindex $locno@r{, convenience variable}
> +When your program stops on a breakpoint, the convenience variables
> +@samp{$bkptno} and @samp{$locno} are respectively set to the number of
> +the encountered breakpoint and the number of the breakpoint's code location:
> +@smallexample
> +Thread 1 "zeoes" hit Breakpoint 2.1, some_func () at zeoes.c:8
> +8	  printf("some func\n");
> +(gdb) p $bkptno
> +$5 = 2
> +(gdb) p $locno
> +$6 = 1
> +(gdb)
> +@end smallexample
> +
> +Note that @samp{$bkptno} and @samp{$bpnum} are not equivalent:
> +@samp{$bkptno} is set to the breakpoint number @b{last hit}, while
> +@samp{$bpnum} is set to the breakpoint number @b{last set}.
> +
> +
> +If the encountered breakpoint has only one code location, @samp{$locno} is set
> +to 1:
> +@smallexample
> +Breakpoint 1, main (argc=1, argv=0x7fffffffe018) at zeoes.c:24
> +24	  if (argc > 1)
> +(gdb) p $bkptno
> +$3 = 1
> +(gdb) p $locno
> +$4 = 1
> +(gdb)
> +@end smallexample
> +
> +The @samp{$bkptno} and @samp{$locno} variables can typically be used
> +in a breakpoint command list.
> +(@pxref{Break Commands, ,Breakpoint Command Lists}). For example, as
> +part of the breakpoint command list, you can disable completely the
> +encountered breakpoint using @samp{disable $bkptno} or disable the
> +specific encountered breakpoint location using @samp{disable
> +$bkptno.$locno}.
>  
> 
>  @table @code
>  @item break @var{locspec}
> @@ -5739,6 +5795,13 @@ Expressions}).
>  Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
>  disabled within a @var{command-list}.
>  
> 
> +Inside a command list, you can use the command
> +@kbd{disable $bkptno} to disable the encountered breakpoint.
> +
> +If your breakpoint has several code locations, the command
> +@kbd{disable $bkptno.$locno} will disable the specific breakpoint code
> +location encountered.
> +
>  You can use breakpoint commands to start your program up again.  Simply
>  use the @code{continue} command, or @code{step}, or any other command
>  that resumes execution.
> @@ -32570,6 +32633,20 @@ line="13",arch="i386:x86_64"@}
>  (gdb)
>  @end smallexample
>  
> 
> +For a @samp{breakpoint-hit} stopped reason, when the breakpoint
> +encountered has multiple locations, the field @samp{bkptno} is
> +followed by the field @samp{locno}.
> +
> +@smallexample
> +-exec-continue
> +^running
> +(gdb)
> +@@Hello world
> +*stopped,reason="breakpoint-hit",disp="keep",bkptno="2",locno="3",frame=@{
> +func="foo",args=[],file="hello.c",fullname="/home/foo/bar/hello.c",
> +line="13",arch="i386:x86_64"@}
> +(gdb)
> +@end smallexample
>  
> 
>  @subheading The @code{-exec-finish} Command
>  @findex -exec-finish
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 02c98b50c8c..e5ad062a914 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -8494,7 +8494,21 @@ print_stop_location (const target_waitstatus &ws)
>       LOCATION: Print only location
>       SRC_AND_LOC: Print location and source line.  */
>    if (do_frame_printing)
> -    print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    {
> +      if (tp->control.stop_bpstat != nullptr)
> +	{
> +	  const struct breakpoint *b = tp->control.stop_bpstat->breakpoint_at;
> +
> +	  if (b != nullptr)
> +	    {
> +	      int locno = bpstat_locno (tp->control.stop_bpstat);
> +	      set_internalvar_integer (lookup_internalvar ("bkptno"), b->number);
> +	      set_internalvar_integer (lookup_internalvar ("locno"),
> +				       (locno > 0 ? locno : 1));
> +	    }
> +	}
> +      print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    }
>  }
>  
> 
>  /* See infrun.h.  */
> diff --git a/gdb/testsuite/gdb.ada/bp_inlined_func.exp b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> index 076e8c2425f..3f94c163819 100644
> --- a/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> +++ b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> @@ -42,7 +42,7 @@ gdb_test "break read_small" \
>  for {set i 0} {$i < 4} {incr i} {
>      with_test_prefix "iteration $i" {
>  	gdb_test "continue" \
> -	    "Breakpoint $decimal, b\\.read_small \\(\\).*" \
> +	    "Breakpoint $bkptno_num_re, b\\.read_small \\(\\).*" \
>  	    "stopped in read_small"
>      }
>  }
> diff --git a/gdb/testsuite/gdb.ada/operator_bp.exp b/gdb/testsuite/gdb.ada/operator_bp.exp
> index 655e7af479f..e3928419ed6 100644
> --- a/gdb/testsuite/gdb.ada/operator_bp.exp
> +++ b/gdb/testsuite/gdb.ada/operator_bp.exp
> @@ -56,7 +56,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to \"$op\""
>  }
>  
> 
> @@ -86,7 +86,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to ops.\"$op\""
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> index b540df973a3..742315178e3 100644
> --- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> +++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> @@ -140,11 +140,11 @@ with_test_prefix "scenario 1" {
>      gdb_run_cmd
>  
> 
>      # Check our conditional breakpoints.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> @@ -208,11 +208,11 @@ with_test_prefix "scenario 2" {
>      gdb_run_cmd
>  
> 
>      # Check that we hit enabled locations only.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> diff --git a/gdb/testsuite/gdb.base/ctxobj.exp b/gdb/testsuite/gdb.base/ctxobj.exp
> index 9c010f54d79..0b589a7d6e6 100644
> --- a/gdb/testsuite/gdb.base/ctxobj.exp
> +++ b/gdb/testsuite/gdb.base/ctxobj.exp
> @@ -67,9 +67,16 @@ gdb_test "break ctxobj-f.c:$bp_location" \
>           "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
>           "break in get_version functions"
>  
> 
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_1 \\(\\).*" \
> -         "continue to get_version_1"
> +global expect_out
> +set test "continue to get_version_1"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_1 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  # Try printing "this_version_num".  There are two global variables
>  # with that name, and some systems such as GNU/Linux merge them
> @@ -100,10 +107,15 @@ gdb_test "print this_version_num == v" \
>          "print libctxobj1's this_version_num from symtab"
>  
> 
>  # Do the same, but from get_version_2.
> -
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_2 \\(\\).*" \
> -         "continue to get_version_2"
> +set test "continue to get_version_2"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_2 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  gdb_test "print this_version_num == v" \
>           " = 1" \
> diff --git a/gdb/testsuite/gdb.base/ena-dis-br.exp b/gdb/testsuite/gdb.base/ena-dis-br.exp
> index 24925cf7185..04b3f134b44 100644
> --- a/gdb/testsuite/gdb.base/ena-dis-br.exp
> +++ b/gdb/testsuite/gdb.base/ena-dis-br.exp
> @@ -67,14 +67,21 @@ gdb_test "info break $bp" \
>  # See the comments in condbreak.exp for "run until breakpoint at
>  # marker1" for an explanation of the xfail below.
>  set test "continue to break marker1"
> +set bpno 0
>  gdb_test_multiple "continue" "$test" {
> -    -re "Breakpoint \[0-9\]*, marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	pass "$test"
>      }
> -    -re "Breakpoint \[0-9\]*, $hex in marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), $hex in marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	xfail "$test"
>      }
>  }
> +# Verify the $bkptno convenience variable is equal to the hit bpno.
> +gdb_test "print \$bkptno" " = $bpno" "$test \$bkptno is $bpno"
> +# Verify the $locno is 1, as there is only one code location.
> +gdb_test "print \$locno" " = 1" "$test \$locno is 1"
>  
> 
>  gdb_test_no_output "delete $bp" "delete break marker1"
>  
> 
> @@ -359,7 +366,8 @@ with_test_prefix "4th breakpoint" {
>  }
>  
> 
>  # Perform tests for disable/enable commands on multiple
> -# locations and breakpoints.
> +# code locations and breakpoints.  If a breakpoint has only one code location,
> +# enable/disable num  and enable/disable num.1 should be equivalent.
>  #
>  # WHAT - the command to test (disable/enable).
>  #
> @@ -372,7 +380,7 @@ proc test_ena_dis_br { what } {
>      global b3
>      global b4
>      global gdb_prompt
> -    
> +
>      # OPPOS    - the command opposite to WHAT.
>      # WHAT_RES - whether breakpoints are expected to end
>      #            up enabled or disabled.
> @@ -395,13 +403,13 @@ proc test_ena_dis_br { what } {
>  	set p2 "pass"
>      }
>  
> 
> -    # Now enable(disable) $b.1 $b2.1.
> +    # Now enable(disable) $b1.1 $b2.1.
>      gdb_test_no_output "$what $b1.1 $b2.1" "$what \$b1.1 \$b2.1"
>      set test1 "${what}d \$b1.1 and \$b2.1"
>  
> 
>      # Now $b1.1 and $b2.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -       -re "(${b1}.1)(\[^\n\r\]*)( n.*)(${b2}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +       -re "(${b1})(\[^\n\r\]*)( n.*)(${b2})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> @@ -420,19 +428,16 @@ proc test_ena_dis_br { what } {
>         "${what}d \$b1"
>  
> 
>      gdb_test_no_output "$oppos $b3" "$oppos \$b3"
> +    # Now $b4 $b3 should be enabled(disabled)
> +    set test1 "${what}d \$b4 and \$b3"
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $oppos_res.*).*(${b4})(\[^\n\r\]*)( $oppos_res.*)" "$test1"
> +
>      gdb_test_no_output "$what $b4 $b3.1" "$what \$b4 \$b3.1"
> -    set test1 "${what}d \$b4 and \$b3.1,remain ${oppos}d \$b3"
> +    set test1 "${what}d \$b4 and \$b3.1, changing \$b3"
> +
> +    # Now $b4 $b3 should be enabled(disabled)
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $what_res.*).*(${b4})(\[^\n\r\]*)( $what_res.*)" "$test1"
>  
> 
> -    # Now $b4 $b3.1 should be enabled(disabled) and
> -    # $b3 should remain disabled(enabled).
> -    gdb_test_multiple "info break" "$test1" {
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b3}.1)(\[^\n\r\]*)( n.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p1 "$test1"
> -       }
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p2 "$test1"
> -       }
> -    }
>  
> 
>      # Now enable(disable) '$b4.1 fooobaar'.  This should error on
>      # fooobaar.
> @@ -443,7 +448,7 @@ proc test_ena_dis_br { what } {
>  
> 
>      # $b4.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -        -re "(${b4}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +        -re "(${b4})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.base/foll-exec-mode.exp b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> index 918f3e4fd5f..cb6d975a767 100644
> --- a/gdb/testsuite/gdb.base/foll-exec-mode.exp
> +++ b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> @@ -99,7 +99,7 @@ proc do_catch_exec_test { } {
>  # before re-running.
>  
> 
>  proc do_follow_exec_mode_tests { mode cmd infswitch } {
> -    global binfile srcfile srcfile2 testfile testfile2
> +    global binfile srcfile srcfile2 testfile testfile2 bkptno_numopt_re
>      global gdb_prompt
>  
> 
>      with_test_prefix "$mode,$cmd,$infswitch" {
> @@ -125,7 +125,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  	# Set up the output we expect to see after we execute past the exec.
>  	#
>  	set execd_line [gdb_get_line_number "after-exec" $srcfile2]
> -	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint .,.*${srcfile2}:${execd_line}.*$gdb_prompt $"
> +	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint ${bkptno_numopt_re},.*${srcfile2}:${execd_line}.*$gdb_prompt $"
>  
> 
>  	# Set a breakpoint after the exec call if we aren't single-stepping
>  	# past it.
> @@ -189,7 +189,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  		send_gdb "y\n"
>  		exp_continue
>  	    }
> -	    -re "Starting program: .*$expected_inf.*Breakpoint .,.*\r\n$gdb_prompt $" {
> +	    -re "Starting program: .*$expected_inf.*Breakpoint $bkptno_numopt_re,.*\r\n$gdb_prompt $" {
>  		pass $test
>  	    }
>  	}
> diff --git a/gdb/testsuite/gdb.base/pie-fork.exp b/gdb/testsuite/gdb.base/pie-fork.exp
> index efc357d39a2..19e9d3a5537 100644
> --- a/gdb/testsuite/gdb.base/pie-fork.exp
> +++ b/gdb/testsuite/gdb.base/pie-fork.exp
> @@ -54,10 +54,10 @@ proc_with_prefix test_detach_on_fork_follow_child {} {
>  proc_with_prefix test_no_detach_on_fork {} {
>      setup_test "off"
>  
> 
> -    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2.1, break_here.*" \
>  	     "continue from thread 1.1"
>      gdb_test "thread 2.1"
> -    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2.2, break_here.*" \
>  	     "continue from thread 2.1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/step-over-exit.exp b/gdb/testsuite/gdb.base/step-over-exit.exp
> index f8bd99980fe..575319c564c 100644
> --- a/gdb/testsuite/gdb.base/step-over-exit.exp
> +++ b/gdb/testsuite/gdb.base/step-over-exit.exp
> @@ -91,7 +91,7 @@ delete_breakpoints
>  
> 
>  gdb_test "break marker"
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_num_re, .*" \
>      "continue to marker, first time"
>  
> 
>  # Step 2, create a breakpoint which evaluates false, and force it
> @@ -120,5 +120,5 @@ gdb_test "inferior 1" ".*Switching to inferior 1.*" \
>  # Switch back to the parent process, continue to the marker to
>  # test GDBserver's state is still correct.
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_numopt_re, .*" \
>      "continue to marker, second time"
> diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
> index 47a2a5dcb7c..fa098602c31 100644
> --- a/gdb/testsuite/gdb.cp/mb-inline.exp
> +++ b/gdb/testsuite/gdb.cp/mb-inline.exp
> @@ -46,7 +46,7 @@ gdb_test "info break" \
>      "\[\r\n\]1\.1.* y .* at .*$hdrfile:$bp_location.*\[\r\n\]1\.2.* y .* at .*$hdrfile:$bp_location.*"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo \\(i=1\\).*" \
> @@ -59,7 +59,7 @@ gdb_test "continue" \
>  gdb_test_no_output "disable 1.2" "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
>  
> 
>  gdb_test_multiple "info break" "disabled breakpoint 1.2" {
>      -re "1\.2.* n .* at .*$hdrfile:$bp_location.*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
> index 6c988e7335e..0c0d46fcb7a 100644
> --- a/gdb/testsuite/gdb.cp/mb-templates.exp
> +++ b/gdb/testsuite/gdb.cp/mb-templates.exp
> @@ -42,7 +42,7 @@ gdb_run_cmd
>  
> 
>  set test "initial condition: run to breakpoint"
>  gdb_test_multiple "" $test {
> -    -re "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
> +    -re "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
>  	pass $test
>  	break
>      }
> @@ -67,7 +67,7 @@ gdb_test_no_output {condition $bpnum i==1} \
>      "separate condition: set condition"
>      
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo<double> \\(i=1\\).*" \
> @@ -79,7 +79,7 @@ gdb_test "continue" \
>  gdb_test_no_output {disable $bpnum.1} "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
>  
> 
>  # Try disabling entire breakpoint
>  gdb_test_no_output {enable $bpnum.1} "disabling location: enable"
> diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
> index 06adf82ecbb..0ed9eae055b 100644
> --- a/gdb/testsuite/gdb.cp/ovldbreak.exp
> +++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
> @@ -380,7 +380,7 @@ gdb_test "info break" $bptable "breakpoint info (after setting on all)"
>  
> 
>  # Run through each breakpoint.
>  proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
> -    global gdb_prompt hex decimal srcfile
> +    global gdb_prompt hex decimal srcfile bkptno_num_re
>  
> 
>      if {$argument == ""} {
>          set actuals ""
> @@ -398,11 +398,11 @@ proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
>      }
>  
> 
>      gdb_test_multiple "continue" "continue to bp overloaded : $argtype" {
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              pass "continue to bp overloaded : $argtype"
>          }
>  
> 
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              if $might_kfail {
>                  kfail "c++/8130" "continue to bp overloaded : $argtype"
>              } else {
> diff --git a/gdb/testsuite/gdb.gdb/python-helper.exp b/gdb/testsuite/gdb.gdb/python-helper.exp
> index 6db8bf0df50..30eb6038f3a 100644
> --- a/gdb/testsuite/gdb.gdb/python-helper.exp
> +++ b/gdb/testsuite/gdb.gdb/python-helper.exp
> @@ -49,7 +49,7 @@ gdb_exit
>  # The main test.  This is called by the self-test framework once GDB
>  # has been started on a copy of itself.
>  proc test_python_helper {} {
> -    global py_helper_script decimal hex gdb_prompt
> +    global py_helper_script decimal hex gdb_prompt bkptno_numopt_re
>      global inferior_spawn_id
>  
> 
>      # Source the python helper script.  This script registers the
> @@ -233,7 +233,7 @@ proc test_python_helper {} {
>      # GDB stopping at the value_print breakpoint again.
>      send_inferior "ptype global_c\n"
>      gdb_test_multiple "" "hit breakpoint in outer gdb again" {
> -	-re "Breakpoint $decimal, c_print_type .*\\(outer-gdb\\) $" {
> +	-re "Breakpoint $bkptno_numopt_re, c_print_type .*\\(outer-gdb\\) $" {
>  	    pass $gdb_test_name
>  	}
>      }
> diff --git a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> index 19ccbe85e04..c080955049c 100644
> --- a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> +++ b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> @@ -69,7 +69,7 @@ if { $use_second_inferior } {
>  	"\\^running.*" \
>  	"run inferior 2"
>  
> 
> -    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\""} \
> +    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\"" "locno=\"[0-9]+\""} \
>  	"inferior i2 stops at all_threads_started"
>  
> 
>      mi_send_resuming_command "exec-continue --thread-group i2" \
> diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> index d78c96ddef1..9eec083068b 100644
> --- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> +++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> @@ -307,8 +307,13 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  	    # Consume MI event output.
>  	    with_spawn_id $mi_spawn_id {
> -		mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> -		    "$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		if { $inf == 1 } {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		} else {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} "stop at breakpoint in main"
> +		}
>  	    }
>  
> 
>  	    if { $mode == "all-stop" } {
> @@ -330,9 +335,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		    # Consume MI output.
>  		    with_spawn_id $mi_spawn_id {
> -			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			    "thread $inf.$thread stops MI"
> +			if { $inf == 1} {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +				"thread $inf.$thread stops MI"
> +			} else {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +				"thread $inf.$thread stops MI"
> +			}
>  		    }
>  		}
>  
> 
> @@ -359,9 +370,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		# Consume MI output.
>  		with_spawn_id $mi_spawn_id {
> -		    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			"thread $inf.2 stops MI"
> +		    if { $inf == 1} {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +			    "thread $inf.2 stops MI"
> +		    } else {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +			    "thread $inf.2 stops MI"
> +		    }
>  		}
>  	    }
>  	}
> @@ -434,7 +451,7 @@ proc_with_prefix test_setup { mode } {
>  
> 
>  	with_spawn_id $mi_spawn_id {
>  	    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" "$decimal" \
> -		{"" "disp=\"del\""} "main stop"
> +		{"" "disp=\"del\"" "locno=\"[0-9]+\""} "main stop"
>  	}
>  
> 
>  	# Consume CLI output.
> diff --git a/gdb/testsuite/gdb.multi/multi-arch-exec.exp b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> index a1496fb5571..dfdb746c65e 100644
> --- a/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> +++ b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> @@ -148,6 +148,7 @@ proc build_executables { first_arch } {
>  }
>  
> 
>  proc do_test { first_arch mode selected_thread } {
> +        global bkptno_numopt_re
>  	set from_exec "$first_arch-multi-arch-exec"
>  
> 
>  	clean_restart ${from_exec}
> @@ -169,7 +170,7 @@ proc do_test { first_arch mode selected_thread } {
>  
> 
>  	# Test that GDB updates the target description / arch successfuly
>  	# after the exec.
> -	gdb_test "continue" "Breakpoint 2, main.*" "continue across exec that changes architecture"
> +	gdb_test "continue" "Breakpoint $bkptno_numopt_re, main.*" "continue across exec that changes architecture"
>  }
>  
> 
>  # Test both arch1=>arch2 and arch2=>arch1.
> diff --git a/gdb/testsuite/gdb.multi/run-only-second-inf.exp b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> index fec2575f904..b94689d0bfa 100644
> --- a/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> +++ b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> @@ -46,5 +46,5 @@ gdb_load $binfile
>  if {[gdb_start_cmd] < 0} {
>      fail "start the second inf"
>  } else {
> -    gdb_test "" ".*reakpoint ., main .*${srcfile}.*" "start the second inf"
> +    gdb_test "" ".*reakpoint $bkptno_numopt_re, main .*${srcfile}.*" "start the second inf"
>  }
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> index cbccba19d12..3c079facced 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> @@ -27,7 +27,7 @@ if {[build_executable "failed to build" $testfile $srcfile {debug}]} {
>  # child.  Can be either "kill", "detach", or "exit" (to continue it to
>  # normal exit).
>  proc do_test {dispose} {
> -    global binfile
> +    global binfile bkptno_numopt_re
>  
> 
>      clean_restart $binfile
>  
> 
> @@ -77,7 +77,7 @@ proc do_test {dispose} {
>      #  Command aborted.
>      #  (gdb)
>      #
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker .*" \
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker .*" \
>  	"continue in inferior 1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi.exp b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> index e4329dca6c2..0fc1bee762f 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> @@ -84,11 +84,11 @@ if [skip_hw_watchpoint_multi_tests] {
>  	"Hardware access \\(read/write\\) watchpoint \[0-9\]+: c\r\n\r\nOld value = 0\r\nNew value = 3\r\n.*" \
>  	"catch c on inferior 2"
>  
> 
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 2"
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 2"
>  
> 
>      gdb_test "inferior 1" "witching to inferior 1 .*" "switch back to inferior 1 again"
>  
> 
>      gdb_test "continue" "Hardware access \\(read/write\\) watchpoint \[0-9\]+: b\r\n\r\nOld value = 0\r\nNew value = 2\r\n.*" "catch b on inferior 1"
>  }
>  
> 
> -gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 1"
> +gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 1"
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 402450152ac..5e4c793598e 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -227,6 +227,14 @@ set inferior_exited_re "(?:\\\[Inferior \[0-9\]+ \\(\[^\n\r\]*\\) exited)"
>  # E.g., $1, $2, etc.
>  set valnum_re "\\\$$decimal"
>  
> 
> +# A regular expression that matches a breakpoint hit with a breakpoint
> +# having several code locations.
> +set bkptno_num_re "$decimal\\.$decimal"
> +
> +# A regular expression that matches a breakpoint hit
> +# with one or several code locations.
> +set bkptno_numopt_re "($decimal\\.$decimal|$decimal)"
> +
>  ### Only procedures should come after this point.
>  
> 
>  #
> @@ -662,6 +670,7 @@ proc gdb_breakpoint { linespec args } {
>  
> 
>  proc runto { linespec args } {
>      global gdb_prompt
> +    global bkptno_numopt_re
>      global decimal
>  
> 
>      delete_breakpoints
> @@ -699,7 +708,7 @@ proc runto { linespec args } {
>  	    }
>  	    return 1
>  	}
> -	-re "Breakpoint \[0-9\]*, \[0-9xa-f\]* in .*$gdb_prompt $" { 
> +	-re "Breakpoint $bkptno_numopt_re, \[0-9xa-f\]* in .*$gdb_prompt $" {
>  	    if { $print_pass } {
>  		pass $test_name
>  	    }
> diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
> index e578a7e6f9b..ea66fdcabf8 100644
> --- a/gdb/testsuite/lib/mi-support.exp
> +++ b/gdb/testsuite/lib/mi-support.exp
> @@ -1195,11 +1195,11 @@ proc mi_detect_async {} {
>  # filename of a file without debug info.  ARGS should not include [] the
>  # list of argument is enclosed in, and other regular expressions should
>  # not include quotes.
> -# If EXTRA is a list of one element, it's the regular expression
> +# EXTRA can be a list of one, two or three elements.
> +# The first element is the regular expression
>  # for output expected right after *stopped, and before GDB prompt.
> -# If EXTRA is a list of two elements, the first element is for
> -# output right after *stopped, and the second element is output
> -# right after reason field.  The regex after reason should not include
> +# The third element is the regulation expression for the locno
> +# right after bkptno field.  The locno regex should not include
>  # the comma separating it from the following fields.
>  #
>  # When we fail to match output at all, -1 is returned.  If FILE does
> @@ -1224,7 +1224,14 @@ proc mi_expect_stop { reason func args file line extra test } {
>  
> 
>      set after_stopped ""
>      set after_reason ""
> -    if { [llength $extra] == 2 } {
> +    set locno ""
> +    if { [llength $extra] == 3 } {
> +	set after_stopped [lindex $extra 0]
> +	set after_reason [lindex $extra 1]
> +	set after_reason "${after_reason},"
> +	set locno [lindex $extra 2]
> +	set locno "${locno},"
> +    } elseif { [llength $extra] == 2 } {
>  	set after_stopped [lindex $extra 0]
>  	set after_reason [lindex $extra 1]
>  	set after_reason "${after_reason},"
> @@ -1298,10 +1305,12 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set ebn ""
>      if { $reason == "breakpoint-hit" } {
>  	set bn {bkptno="[0-9]+",}
> +	set bn "${bn}${locno}"
>      } elseif { $reason == "solib-event" } {
>  	set bn ".*"
>      } elseif { $reason == "exception-caught" } {
>  	set ebn {bkptno="[0-9]+",}
> +	set ebn "${ebn}${locno}"
>  	set bn ".*"
>  	set reason "breakpoint-hit"
>      }
> @@ -1315,6 +1324,7 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set a $after_reason
>  
> 
>      verbose -log "mi_expect_stop: expecting: \\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
> +
>      gdb_expect {
>  	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
>  	    pass "$test"



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-06-06  9:45 [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno Philippe Waroquiers
                   ` (2 preceding siblings ...)
  2022-06-19 17:46 ` Philippe Waroquiers
@ 2022-06-26 17:27 ` Philippe Waroquiers
  2022-07-22 16:57 ` Philippe Waroquiers
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Philippe Waroquiers @ 2022-06-26 17:27 UTC (permalink / raw)
  To: gdb-patches

Ping ^ 3
(Eli reviewed the doc, Keith did a first review)

Thanks
Philippe



On Mon, 2022-06-06 at 11:45 +0200, Philippe Waroquiers wrote:
> Before this patch, when a breakpoint that has multiple locations is reached,
> GDB printed:
>   Thread 1 "zeoes" hit Breakpoint 1, some_func () at somefunc1.c:5
> 
> This patch changes the message so that bkpt_print_id prints the precise
> encountered breakpoint:
>   Thread 1 "zeoes" hit Breakpoint 1.2, some_func () at somefunc1.c:5
> 
> In mi mode, bkpt_print_id also (optionally) prints a new table field "locno":
>   locno is printed when the breakpoint has more than one location.
> Note that according to the GDB user manual node 'GDB/MI Development and Front
> Ends', it is ok to add new fields without changing the MI version.
> 
> Also, when a breakpoint is reached, the convenience variables
> $bkptno and $locno are set to the encountered breakpoint number
> and location number.
> 
> $bkptno and $locno can a.o. be used in the command list of a breakpoint,
> to disable the specific encountered breakpoint, e.g.
>    disable $bkptno.$locno
> 
> In case the breakpoint has only one location, $locno is still set to
> the value 1, so as to allow a command such as:
>   disable $bkptno.$locno
> even when the breakpoint has only one location.
> 
> This also fixes a strange behaviour: when a breakpoint X has only
> one location,
>   enable|disable X.1
> is accepted but transforms the breakpoint in a multiple locations
> breakpoint having only one location.
> 
> The changes in RFA v3 handle the additional comments of Eli:
>  GDB/NEW:
>   - Use max 80-column
>   - Use 'code location' instead of 'location'.
>   - Fix typo $bkpno
>   - Ensure that disable $bkptno and disable $bkptno.$locno have
>     each their explanation inthe example
>   - Reworded the 'breakpoint-hit' paragraph.
>  gdb.texinfo:
>   - Use 'code location' instead of 'location'.
>   - Add a note to clarify the distinction between $bkptno and $bpnum.
>   - Use @kbd instead of examples with only one command.
> 
> Compared to RFA v1, the changes in v2 handle the comments given by
> Keith Seitz and Eli Zaretskii:
>   - Use %s for the result of paddress
>   - Use bkptno_numopt_re instead of 2 different -re cases
>   - use C@t{++}
>   - Add index entries for $bkptno and $locno
>   - Added an example for "locno" in the mi interface
>   - Added examples in the Break command manual.
> ---
>  gdb/NEWS                                      | 21 +++++
>  gdb/ada-lang.c                                |  2 +-
>  gdb/break-catch-syscall.c                     |  2 +-
>  gdb/break-catch-throw.c                       |  2 +-
>  gdb/breakpoint.c                              | 93 +++++++++++++++----
>  gdb/breakpoint.h                              | 14 +++
>  gdb/doc/gdb.texinfo                           | 83 ++++++++++++++++-
>  gdb/infrun.c                                  | 16 +++-
>  gdb/testsuite/gdb.ada/bp_inlined_func.exp     |  2 +-
>  gdb/testsuite/gdb.ada/operator_bp.exp         |  4 +-
>  .../gdb.base/condbreak-multi-context.exp      |  8 +-
>  gdb/testsuite/gdb.base/ctxobj.exp             | 26 ++++--
>  gdb/testsuite/gdb.base/ena-dis-br.exp         | 41 ++++----
>  gdb/testsuite/gdb.base/foll-exec-mode.exp     |  6 +-
>  gdb/testsuite/gdb.base/pie-fork.exp           |  4 +-
>  gdb/testsuite/gdb.base/step-over-exit.exp     |  4 +-
>  gdb/testsuite/gdb.cp/mb-inline.exp            |  4 +-
>  gdb/testsuite/gdb.cp/mb-templates.exp         |  6 +-
>  gdb/testsuite/gdb.cp/ovldbreak.exp            |  6 +-
>  gdb/testsuite/gdb.gdb/python-helper.exp       |  4 +-
>  .../gdb.mi/interrupt-thread-group.exp         |  2 +-
>  .../gdb.mi/user-selected-context-sync.exp     | 35 +++++--
>  gdb/testsuite/gdb.multi/multi-arch-exec.exp   |  3 +-
>  .../gdb.multi/run-only-second-inf.exp         |  2 +-
>  .../gdb.multi/watchpoint-multi-exit.exp       |  4 +-
>  gdb/testsuite/gdb.multi/watchpoint-multi.exp  |  4 +-
>  gdb/testsuite/lib/gdb.exp                     | 11 ++-
>  gdb/testsuite/lib/mi-support.exp              | 20 +++-
>  28 files changed, 335 insertions(+), 94 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 960f90b4387..a5602deee2b 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -34,6 +34,21 @@
>       whitespace from each line before using the string as the help
>       output.
>  
> 
> +* When a breakpoint with multiple code locations is hit, GDB now prints
> +  the code location using the syntax <breakpoint_number>.<location_number>
> +  such as in:
> +     Thread 1 "zeoes" hit Breakpoint 2.3, some_func () at zeoes.c:8
> +
> +* When a breakpoint is hit, GDB now sets the convenience variables $bkptno and
> +  $locno to the hit breakpoint number and code location number.
> +  This allows to disable the last hit breakpoint using
> +     (gdb) disable $bkptno
> +   or disable only the specific breakpoint code location using
> +     (gdb) disable $bkptno.$locno
> +  These commands can be used inside the command list of a breakpoint to
> +  automatically disable the just encountered breakpoint (or the just
> +  encountered specific breakpoint code location).
> +
>  * New commands
>  
> 
>  maintenance set ignore-prologue-end-flag on|off
> @@ -50,6 +65,12 @@ maintenance info line-table
>    entry corresponds to an address where a breakpoint should be placed
>    to be at the first instruction past a function's prologue.
>  
> 
> +* MI changes
> +
> + ** The async record stating the stopped reason 'breakpoint-hit' now
> +    contains an optional field locno giving the code location number
> +    when the breakpoint has multiple code locations.
> +
>  * Python API
>  
> 
>    ** New function gdb.format_address(ADDRESS, PROGSPACE, ARCHITECTURE),
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 6ab01fd27d4..bbae76f39ac 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -12348,7 +12348,7 @@ ada_catchpoint::print_it (const bpstat *bs) const
>  
> 
>    uiout->text (disposition == disp_del
>  	       ? "\nTemporary catchpoint " : "\nCatchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    /* ada_exception_name_addr relies on the selected frame being the
> diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
> index 06d48466de7..82229de33f7 100644
> --- a/gdb/break-catch-syscall.c
> +++ b/gdb/break-catch-syscall.c
> @@ -218,7 +218,7 @@ syscall_catchpoint::print_it (const bpstat *bs) const
>  						: EXEC_ASYNC_SYSCALL_RETURN));
>        uiout->field_string ("disp", bpdisp_text (b->disposition));
>      }
> -  uiout->field_signed ("bkptno", b->number);
> +  print_num_locno (bs, uiout);
>  
> 
>    if (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY)
>      uiout->text (" (call to syscall ");
> diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
> index 66cf80be1c5..5b6f5d9eca1 100644
> --- a/gdb/break-catch-throw.c
> +++ b/gdb/break-catch-throw.c
> @@ -257,7 +257,7 @@ exception_catchpoint::print_it (const bpstat *bs) const
>    bp_temp = disposition == disp_del;
>    uiout->text (bp_temp ? "Temporary catchpoint "
>  		       : "Catchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text ((kind == EX_EVENT_THROW ? " (exception thrown), "
>  		: (kind == EX_EVENT_CATCH ? " (exception caught), "
>  		   : " (exception rethrown), ")));
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index ed932a19ed7..c89c800f32f 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -820,6 +820,19 @@ get_breakpoint (int num)
>    return nullptr;
>  }
>  
> 
> +/* Return TRUE if NUM refer to an existing breakpoint that has
> +   multiple code locations.  */
> +
> +static bool
> +has_multiple_locations (int num)
> +{
> +  for (breakpoint *b : all_breakpoints ())
> +    if (b->number == num)
> +      return b->loc != nullptr && b->loc->next != nullptr;
> +
> +  return false;
> +}
> +
>  \f
>  
> 
>  /* Mark locations as "conditions have changed" in case the target supports
> @@ -4451,15 +4464,7 @@ bpstat_explains_signal (bpstat *bsp, enum gdb_signal sig)
>    return false;
>  }
>  
> 
> -/* Put in *NUM the breakpoint number of the first breakpoint we are
> -   stopped at.  *BSP upon return is a bpstat which points to the
> -   remaining breakpoints stopped at (but which is not guaranteed to be
> -   good for anything but further calls to bpstat_num).
> -
> -   Return 0 if passed a bpstat which does not indicate any breakpoints.
> -   Return -1 if stopped at a breakpoint that has been deleted since
> -   we set it.
> -   Return 1 otherwise.  */
> +/* See breakpoint.h.  */
>  
> 
>  int
>  bpstat_num (bpstat **bsp, int *num)
> @@ -4481,6 +4486,57 @@ bpstat_num (bpstat **bsp, int *num)
>    return 1;
>  }
>  
> 
> +/* See breakpoint.h  */
> +
> +int
> +bpstat_locno (const bpstat *bs)
> +{
> +  const struct breakpoint *b = bs->breakpoint_at;
> +  const struct bp_location *bl = bs->bp_location_at.get ();
> +
> +  int locno = 0;
> +
> +  if (b != nullptr && b->loc->next != nullptr)
> +    {
> +      const bp_location *bl_i;
> +
> +      for (bl_i = b->loc;
> +	   bl_i != bl && bl_i->next != nullptr;
> +	   bl_i = bl_i->next)
> +	locno++;
> +
> +      if (bl_i == bl)
> +	locno++;
> +      else
> +	{
> +	  warning (_("location number not found for breakpoint %d address %s."),
> +		   b->number, paddress (bl->gdbarch, bl->address));
> +	  locno = 0;
> +	}
> +    }
> +
> +  return locno;
> +}
> +
> +/* See breakpoint.h.  */
> +
> +void
> +print_num_locno (const bpstat *bs, struct ui_out *uiout)
> +{
> +  struct breakpoint *b = bs->breakpoint_at;
> +
> +  if (b == nullptr)
> +    uiout->text (_("deleted breakpoint"));
> +  else
> +    {
> +      uiout->field_signed ("bkptno", b->number);
> +
> +      int locno = bpstat_locno (bs);
> +      if (locno != 0)
> +	uiout->message (".%pF", signed_field ("locno", locno));
> +    }
> +}
> +
>  /* See breakpoint.h.  */
>  
> 
>  void
> @@ -9176,7 +9232,7 @@ ranged_breakpoint::print_it (const bpstat *bs) const
>  		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
> @@ -11610,12 +11666,13 @@ ordinary_breakpoint::print_it (const bpstat *bs) const
>  			   async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> +
>    if (bp_temp)
> -    uiout->message ("Temporary breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Temporary breakpoint ");
>    else
> -    uiout->message ("Breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Breakpoint ");
> +  print_num_locno (bs, uiout);
> +  uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
>  }
> @@ -13220,9 +13277,13 @@ enable_disable_command (const char *args, int from_tty, bool enable)
>  	  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)
> +	      && (bp_loc_range.first == 0
> +		  || (bp_loc_range.first == 1
> +		      && bp_num_range.first == bp_num_range.second
> +		      && !has_multiple_locations (bp_num_range.first))))
>  	    {
> -	      /* Handle breakpoint ids with formats 'x' or 'x-z'.  */
> +	      /* Handle breakpoint ids with formats 'x' or 'x-z'
> +		 or 'y.1' where y has only one code location.  */
>  	      map_breakpoint_number_range (bp_num_range,
>  					   enable
>  					   ? enable_breakpoint
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 566f1285e46..96d61ef5427 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -1231,6 +1231,20 @@ extern enum print_stop_action bpstat_print (bpstat *, int);
>     Return 1 otherwise.  */
>  extern int bpstat_num (bpstat **, int *);
>  
> 
> +/* If BS indicates a breakpoint and this breakpoint has several code locations,
> +   return the location number of BS, otherwise return 0.  */
> +
> +extern int bpstat_locno (const bpstat *bs);
> +
> +/* Print BS breakpoint number optionally followed by a . and breakpoint locno.
> +
> +   For a breakpoint with only one code location, outputs the signed field
> +   "bkptno" breakpoint number of BS (as returned by bpstat_num).
> +   If BS has several code locations, outputs a '.' character followed by
> +   the signed field "locno" (as returned by bpstat_locno).  */
> +
> +extern void print_num_locno (const bpstat *bs, struct ui_out *);
> +
>  /* Perform actions associated with the stopped inferior.  Actually, we
>     just use this for breakpoint commands.  Perhaps other actions will
>     go here later, but this is executed at a late time (from the
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 434add3a663..391b81f8863 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -4338,9 +4338,65 @@ are operated on.
>  @cindex latest breakpoint
>  Breakpoints are set with the @code{break} command (abbreviated
>  @code{b}).  The debugger convenience variable @samp{$bpnum} records the
> -number of the breakpoint you've set most recently; see @ref{Convenience
> -Vars,, Convenience Variables}, for a discussion of what you can do with
> -convenience variables.
> +number of the breakpoint you've set most recently:
> +@smallexample
> +(gdb) b main
> +Breakpoint 1 at 0x11c6: file zeoes.c, line 24.
> +(gdb) p $bpnum
> +$1 = 1
> +@end smallexample
> +
> +A breakpoint may be mapped to multiple code locations for example with
> +inlined functions, Ada generics, C@t{++} templates or overloaded function names.
> +@value{GDBN} then indicates the number of code locations in the breakpoint
> +command output:
> +@smallexample
> +(gdb) b some_func
> +Breakpoint 2 at 0x1179: some_func. (3 locations)
> +(gdb) p $bpnum
> +$2 = 2
> +(gdb)
> +@end smallexample
> +
> +@vindex $bkptno@r{, convenience variable}
> +@vindex $locno@r{, convenience variable}
> +When your program stops on a breakpoint, the convenience variables
> +@samp{$bkptno} and @samp{$locno} are respectively set to the number of
> +the encountered breakpoint and the number of the breakpoint's code location:
> +@smallexample
> +Thread 1 "zeoes" hit Breakpoint 2.1, some_func () at zeoes.c:8
> +8	  printf("some func\n");
> +(gdb) p $bkptno
> +$5 = 2
> +(gdb) p $locno
> +$6 = 1
> +(gdb)
> +@end smallexample
> +
> +Note that @samp{$bkptno} and @samp{$bpnum} are not equivalent:
> +@samp{$bkptno} is set to the breakpoint number @b{last hit}, while
> +@samp{$bpnum} is set to the breakpoint number @b{last set}.
> +
> +
> +If the encountered breakpoint has only one code location, @samp{$locno} is set
> +to 1:
> +@smallexample
> +Breakpoint 1, main (argc=1, argv=0x7fffffffe018) at zeoes.c:24
> +24	  if (argc > 1)
> +(gdb) p $bkptno
> +$3 = 1
> +(gdb) p $locno
> +$4 = 1
> +(gdb)
> +@end smallexample
> +
> +The @samp{$bkptno} and @samp{$locno} variables can typically be used
> +in a breakpoint command list.
> +(@pxref{Break Commands, ,Breakpoint Command Lists}). For example, as
> +part of the breakpoint command list, you can disable completely the
> +encountered breakpoint using @samp{disable $bkptno} or disable the
> +specific encountered breakpoint location using @samp{disable
> +$bkptno.$locno}.
>  
> 
>  @table @code
>  @item break @var{locspec}
> @@ -5739,6 +5795,13 @@ Expressions}).
>  Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
>  disabled within a @var{command-list}.
>  
> 
> +Inside a command list, you can use the command
> +@kbd{disable $bkptno} to disable the encountered breakpoint.
> +
> +If your breakpoint has several code locations, the command
> +@kbd{disable $bkptno.$locno} will disable the specific breakpoint code
> +location encountered.
> +
>  You can use breakpoint commands to start your program up again.  Simply
>  use the @code{continue} command, or @code{step}, or any other command
>  that resumes execution.
> @@ -32570,6 +32633,20 @@ line="13",arch="i386:x86_64"@}
>  (gdb)
>  @end smallexample
>  
> 
> +For a @samp{breakpoint-hit} stopped reason, when the breakpoint
> +encountered has multiple locations, the field @samp{bkptno} is
> +followed by the field @samp{locno}.
> +
> +@smallexample
> +-exec-continue
> +^running
> +(gdb)
> +@@Hello world
> +*stopped,reason="breakpoint-hit",disp="keep",bkptno="2",locno="3",frame=@{
> +func="foo",args=[],file="hello.c",fullname="/home/foo/bar/hello.c",
> +line="13",arch="i386:x86_64"@}
> +(gdb)
> +@end smallexample
>  
> 
>  @subheading The @code{-exec-finish} Command
>  @findex -exec-finish
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 02c98b50c8c..e5ad062a914 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -8494,7 +8494,21 @@ print_stop_location (const target_waitstatus &ws)
>       LOCATION: Print only location
>       SRC_AND_LOC: Print location and source line.  */
>    if (do_frame_printing)
> -    print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    {
> +      if (tp->control.stop_bpstat != nullptr)
> +	{
> +	  const struct breakpoint *b = tp->control.stop_bpstat->breakpoint_at;
> +
> +	  if (b != nullptr)
> +	    {
> +	      int locno = bpstat_locno (tp->control.stop_bpstat);
> +	      set_internalvar_integer (lookup_internalvar ("bkptno"), b->number);
> +	      set_internalvar_integer (lookup_internalvar ("locno"),
> +				       (locno > 0 ? locno : 1));
> +	    }
> +	}
> +      print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    }
>  }
>  
> 
>  /* See infrun.h.  */
> diff --git a/gdb/testsuite/gdb.ada/bp_inlined_func.exp b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> index 076e8c2425f..3f94c163819 100644
> --- a/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> +++ b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> @@ -42,7 +42,7 @@ gdb_test "break read_small" \
>  for {set i 0} {$i < 4} {incr i} {
>      with_test_prefix "iteration $i" {
>  	gdb_test "continue" \
> -	    "Breakpoint $decimal, b\\.read_small \\(\\).*" \
> +	    "Breakpoint $bkptno_num_re, b\\.read_small \\(\\).*" \
>  	    "stopped in read_small"
>      }
>  }
> diff --git a/gdb/testsuite/gdb.ada/operator_bp.exp b/gdb/testsuite/gdb.ada/operator_bp.exp
> index 655e7af479f..e3928419ed6 100644
> --- a/gdb/testsuite/gdb.ada/operator_bp.exp
> +++ b/gdb/testsuite/gdb.ada/operator_bp.exp
> @@ -56,7 +56,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to \"$op\""
>  }
>  
> 
> @@ -86,7 +86,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to ops.\"$op\""
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> index b540df973a3..742315178e3 100644
> --- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> +++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> @@ -140,11 +140,11 @@ with_test_prefix "scenario 1" {
>      gdb_run_cmd
>  
> 
>      # Check our conditional breakpoints.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> @@ -208,11 +208,11 @@ with_test_prefix "scenario 2" {
>      gdb_run_cmd
>  
> 
>      # Check that we hit enabled locations only.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> diff --git a/gdb/testsuite/gdb.base/ctxobj.exp b/gdb/testsuite/gdb.base/ctxobj.exp
> index 9c010f54d79..0b589a7d6e6 100644
> --- a/gdb/testsuite/gdb.base/ctxobj.exp
> +++ b/gdb/testsuite/gdb.base/ctxobj.exp
> @@ -67,9 +67,16 @@ gdb_test "break ctxobj-f.c:$bp_location" \
>           "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
>           "break in get_version functions"
>  
> 
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_1 \\(\\).*" \
> -         "continue to get_version_1"
> +global expect_out
> +set test "continue to get_version_1"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_1 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  # Try printing "this_version_num".  There are two global variables
>  # with that name, and some systems such as GNU/Linux merge them
> @@ -100,10 +107,15 @@ gdb_test "print this_version_num == v" \
>          "print libctxobj1's this_version_num from symtab"
>  
> 
>  # Do the same, but from get_version_2.
> -
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_2 \\(\\).*" \
> -         "continue to get_version_2"
> +set test "continue to get_version_2"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_2 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  gdb_test "print this_version_num == v" \
>           " = 1" \
> diff --git a/gdb/testsuite/gdb.base/ena-dis-br.exp b/gdb/testsuite/gdb.base/ena-dis-br.exp
> index 24925cf7185..04b3f134b44 100644
> --- a/gdb/testsuite/gdb.base/ena-dis-br.exp
> +++ b/gdb/testsuite/gdb.base/ena-dis-br.exp
> @@ -67,14 +67,21 @@ gdb_test "info break $bp" \
>  # See the comments in condbreak.exp for "run until breakpoint at
>  # marker1" for an explanation of the xfail below.
>  set test "continue to break marker1"
> +set bpno 0
>  gdb_test_multiple "continue" "$test" {
> -    -re "Breakpoint \[0-9\]*, marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	pass "$test"
>      }
> -    -re "Breakpoint \[0-9\]*, $hex in marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), $hex in marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	xfail "$test"
>      }
>  }
> +# Verify the $bkptno convenience variable is equal to the hit bpno.
> +gdb_test "print \$bkptno" " = $bpno" "$test \$bkptno is $bpno"
> +# Verify the $locno is 1, as there is only one code location.
> +gdb_test "print \$locno" " = 1" "$test \$locno is 1"
>  
> 
>  gdb_test_no_output "delete $bp" "delete break marker1"
>  
> 
> @@ -359,7 +366,8 @@ with_test_prefix "4th breakpoint" {
>  }
>  
> 
>  # Perform tests for disable/enable commands on multiple
> -# locations and breakpoints.
> +# code locations and breakpoints.  If a breakpoint has only one code location,
> +# enable/disable num  and enable/disable num.1 should be equivalent.
>  #
>  # WHAT - the command to test (disable/enable).
>  #
> @@ -372,7 +380,7 @@ proc test_ena_dis_br { what } {
>      global b3
>      global b4
>      global gdb_prompt
> -    
> +
>      # OPPOS    - the command opposite to WHAT.
>      # WHAT_RES - whether breakpoints are expected to end
>      #            up enabled or disabled.
> @@ -395,13 +403,13 @@ proc test_ena_dis_br { what } {
>  	set p2 "pass"
>      }
>  
> 
> -    # Now enable(disable) $b.1 $b2.1.
> +    # Now enable(disable) $b1.1 $b2.1.
>      gdb_test_no_output "$what $b1.1 $b2.1" "$what \$b1.1 \$b2.1"
>      set test1 "${what}d \$b1.1 and \$b2.1"
>  
> 
>      # Now $b1.1 and $b2.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -       -re "(${b1}.1)(\[^\n\r\]*)( n.*)(${b2}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +       -re "(${b1})(\[^\n\r\]*)( n.*)(${b2})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> @@ -420,19 +428,16 @@ proc test_ena_dis_br { what } {
>         "${what}d \$b1"
>  
> 
>      gdb_test_no_output "$oppos $b3" "$oppos \$b3"
> +    # Now $b4 $b3 should be enabled(disabled)
> +    set test1 "${what}d \$b4 and \$b3"
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $oppos_res.*).*(${b4})(\[^\n\r\]*)( $oppos_res.*)" "$test1"
> +
>      gdb_test_no_output "$what $b4 $b3.1" "$what \$b4 \$b3.1"
> -    set test1 "${what}d \$b4 and \$b3.1,remain ${oppos}d \$b3"
> +    set test1 "${what}d \$b4 and \$b3.1, changing \$b3"
> +
> +    # Now $b4 $b3 should be enabled(disabled)
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $what_res.*).*(${b4})(\[^\n\r\]*)( $what_res.*)" "$test1"
>  
> 
> -    # Now $b4 $b3.1 should be enabled(disabled) and
> -    # $b3 should remain disabled(enabled).
> -    gdb_test_multiple "info break" "$test1" {
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b3}.1)(\[^\n\r\]*)( n.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p1 "$test1"
> -       }
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p2 "$test1"
> -       }
> -    }
>  
> 
>      # Now enable(disable) '$b4.1 fooobaar'.  This should error on
>      # fooobaar.
> @@ -443,7 +448,7 @@ proc test_ena_dis_br { what } {
>  
> 
>      # $b4.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -        -re "(${b4}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +        -re "(${b4})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.base/foll-exec-mode.exp b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> index 918f3e4fd5f..cb6d975a767 100644
> --- a/gdb/testsuite/gdb.base/foll-exec-mode.exp
> +++ b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> @@ -99,7 +99,7 @@ proc do_catch_exec_test { } {
>  # before re-running.
>  
> 
>  proc do_follow_exec_mode_tests { mode cmd infswitch } {
> -    global binfile srcfile srcfile2 testfile testfile2
> +    global binfile srcfile srcfile2 testfile testfile2 bkptno_numopt_re
>      global gdb_prompt
>  
> 
>      with_test_prefix "$mode,$cmd,$infswitch" {
> @@ -125,7 +125,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  	# Set up the output we expect to see after we execute past the exec.
>  	#
>  	set execd_line [gdb_get_line_number "after-exec" $srcfile2]
> -	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint .,.*${srcfile2}:${execd_line}.*$gdb_prompt $"
> +	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint ${bkptno_numopt_re},.*${srcfile2}:${execd_line}.*$gdb_prompt $"
>  
> 
>  	# Set a breakpoint after the exec call if we aren't single-stepping
>  	# past it.
> @@ -189,7 +189,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  		send_gdb "y\n"
>  		exp_continue
>  	    }
> -	    -re "Starting program: .*$expected_inf.*Breakpoint .,.*\r\n$gdb_prompt $" {
> +	    -re "Starting program: .*$expected_inf.*Breakpoint $bkptno_numopt_re,.*\r\n$gdb_prompt $" {
>  		pass $test
>  	    }
>  	}
> diff --git a/gdb/testsuite/gdb.base/pie-fork.exp b/gdb/testsuite/gdb.base/pie-fork.exp
> index efc357d39a2..19e9d3a5537 100644
> --- a/gdb/testsuite/gdb.base/pie-fork.exp
> +++ b/gdb/testsuite/gdb.base/pie-fork.exp
> @@ -54,10 +54,10 @@ proc_with_prefix test_detach_on_fork_follow_child {} {
>  proc_with_prefix test_no_detach_on_fork {} {
>      setup_test "off"
>  
> 
> -    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2.1, break_here.*" \
>  	     "continue from thread 1.1"
>      gdb_test "thread 2.1"
> -    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2.2, break_here.*" \
>  	     "continue from thread 2.1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/step-over-exit.exp b/gdb/testsuite/gdb.base/step-over-exit.exp
> index f8bd99980fe..575319c564c 100644
> --- a/gdb/testsuite/gdb.base/step-over-exit.exp
> +++ b/gdb/testsuite/gdb.base/step-over-exit.exp
> @@ -91,7 +91,7 @@ delete_breakpoints
>  
> 
>  gdb_test "break marker"
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_num_re, .*" \
>      "continue to marker, first time"
>  
> 
>  # Step 2, create a breakpoint which evaluates false, and force it
> @@ -120,5 +120,5 @@ gdb_test "inferior 1" ".*Switching to inferior 1.*" \
>  # Switch back to the parent process, continue to the marker to
>  # test GDBserver's state is still correct.
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_numopt_re, .*" \
>      "continue to marker, second time"
> diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
> index 47a2a5dcb7c..fa098602c31 100644
> --- a/gdb/testsuite/gdb.cp/mb-inline.exp
> +++ b/gdb/testsuite/gdb.cp/mb-inline.exp
> @@ -46,7 +46,7 @@ gdb_test "info break" \
>      "\[\r\n\]1\.1.* y .* at .*$hdrfile:$bp_location.*\[\r\n\]1\.2.* y .* at .*$hdrfile:$bp_location.*"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo \\(i=1\\).*" \
> @@ -59,7 +59,7 @@ gdb_test "continue" \
>  gdb_test_no_output "disable 1.2" "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
>  
> 
>  gdb_test_multiple "info break" "disabled breakpoint 1.2" {
>      -re "1\.2.* n .* at .*$hdrfile:$bp_location.*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
> index 6c988e7335e..0c0d46fcb7a 100644
> --- a/gdb/testsuite/gdb.cp/mb-templates.exp
> +++ b/gdb/testsuite/gdb.cp/mb-templates.exp
> @@ -42,7 +42,7 @@ gdb_run_cmd
>  
> 
>  set test "initial condition: run to breakpoint"
>  gdb_test_multiple "" $test {
> -    -re "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
> +    -re "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
>  	pass $test
>  	break
>      }
> @@ -67,7 +67,7 @@ gdb_test_no_output {condition $bpnum i==1} \
>      "separate condition: set condition"
>      
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo<double> \\(i=1\\).*" \
> @@ -79,7 +79,7 @@ gdb_test "continue" \
>  gdb_test_no_output {disable $bpnum.1} "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
>  
> 
>  # Try disabling entire breakpoint
>  gdb_test_no_output {enable $bpnum.1} "disabling location: enable"
> diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
> index 06adf82ecbb..0ed9eae055b 100644
> --- a/gdb/testsuite/gdb.cp/ovldbreak.exp
> +++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
> @@ -380,7 +380,7 @@ gdb_test "info break" $bptable "breakpoint info (after setting on all)"
>  
> 
>  # Run through each breakpoint.
>  proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
> -    global gdb_prompt hex decimal srcfile
> +    global gdb_prompt hex decimal srcfile bkptno_num_re
>  
> 
>      if {$argument == ""} {
>          set actuals ""
> @@ -398,11 +398,11 @@ proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
>      }
>  
> 
>      gdb_test_multiple "continue" "continue to bp overloaded : $argtype" {
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              pass "continue to bp overloaded : $argtype"
>          }
>  
> 
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              if $might_kfail {
>                  kfail "c++/8130" "continue to bp overloaded : $argtype"
>              } else {
> diff --git a/gdb/testsuite/gdb.gdb/python-helper.exp b/gdb/testsuite/gdb.gdb/python-helper.exp
> index 6db8bf0df50..30eb6038f3a 100644
> --- a/gdb/testsuite/gdb.gdb/python-helper.exp
> +++ b/gdb/testsuite/gdb.gdb/python-helper.exp
> @@ -49,7 +49,7 @@ gdb_exit
>  # The main test.  This is called by the self-test framework once GDB
>  # has been started on a copy of itself.
>  proc test_python_helper {} {
> -    global py_helper_script decimal hex gdb_prompt
> +    global py_helper_script decimal hex gdb_prompt bkptno_numopt_re
>      global inferior_spawn_id
>  
> 
>      # Source the python helper script.  This script registers the
> @@ -233,7 +233,7 @@ proc test_python_helper {} {
>      # GDB stopping at the value_print breakpoint again.
>      send_inferior "ptype global_c\n"
>      gdb_test_multiple "" "hit breakpoint in outer gdb again" {
> -	-re "Breakpoint $decimal, c_print_type .*\\(outer-gdb\\) $" {
> +	-re "Breakpoint $bkptno_numopt_re, c_print_type .*\\(outer-gdb\\) $" {
>  	    pass $gdb_test_name
>  	}
>      }
> diff --git a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> index 19ccbe85e04..c080955049c 100644
> --- a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> +++ b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> @@ -69,7 +69,7 @@ if { $use_second_inferior } {
>  	"\\^running.*" \
>  	"run inferior 2"
>  
> 
> -    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\""} \
> +    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\"" "locno=\"[0-9]+\""} \
>  	"inferior i2 stops at all_threads_started"
>  
> 
>      mi_send_resuming_command "exec-continue --thread-group i2" \
> diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> index d78c96ddef1..9eec083068b 100644
> --- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> +++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> @@ -307,8 +307,13 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  	    # Consume MI event output.
>  	    with_spawn_id $mi_spawn_id {
> -		mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> -		    "$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		if { $inf == 1 } {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		} else {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} "stop at breakpoint in main"
> +		}
>  	    }
>  
> 
>  	    if { $mode == "all-stop" } {
> @@ -330,9 +335,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		    # Consume MI output.
>  		    with_spawn_id $mi_spawn_id {
> -			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			    "thread $inf.$thread stops MI"
> +			if { $inf == 1} {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +				"thread $inf.$thread stops MI"
> +			} else {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +				"thread $inf.$thread stops MI"
> +			}
>  		    }
>  		}
>  
> 
> @@ -359,9 +370,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		# Consume MI output.
>  		with_spawn_id $mi_spawn_id {
> -		    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			"thread $inf.2 stops MI"
> +		    if { $inf == 1} {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +			    "thread $inf.2 stops MI"
> +		    } else {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +			    "thread $inf.2 stops MI"
> +		    }
>  		}
>  	    }
>  	}
> @@ -434,7 +451,7 @@ proc_with_prefix test_setup { mode } {
>  
> 
>  	with_spawn_id $mi_spawn_id {
>  	    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" "$decimal" \
> -		{"" "disp=\"del\""} "main stop"
> +		{"" "disp=\"del\"" "locno=\"[0-9]+\""} "main stop"
>  	}
>  
> 
>  	# Consume CLI output.
> diff --git a/gdb/testsuite/gdb.multi/multi-arch-exec.exp b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> index a1496fb5571..dfdb746c65e 100644
> --- a/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> +++ b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> @@ -148,6 +148,7 @@ proc build_executables { first_arch } {
>  }
>  
> 
>  proc do_test { first_arch mode selected_thread } {
> +        global bkptno_numopt_re
>  	set from_exec "$first_arch-multi-arch-exec"
>  
> 
>  	clean_restart ${from_exec}
> @@ -169,7 +170,7 @@ proc do_test { first_arch mode selected_thread } {
>  
> 
>  	# Test that GDB updates the target description / arch successfuly
>  	# after the exec.
> -	gdb_test "continue" "Breakpoint 2, main.*" "continue across exec that changes architecture"
> +	gdb_test "continue" "Breakpoint $bkptno_numopt_re, main.*" "continue across exec that changes architecture"
>  }
>  
> 
>  # Test both arch1=>arch2 and arch2=>arch1.
> diff --git a/gdb/testsuite/gdb.multi/run-only-second-inf.exp b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> index fec2575f904..b94689d0bfa 100644
> --- a/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> +++ b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> @@ -46,5 +46,5 @@ gdb_load $binfile
>  if {[gdb_start_cmd] < 0} {
>      fail "start the second inf"
>  } else {
> -    gdb_test "" ".*reakpoint ., main .*${srcfile}.*" "start the second inf"
> +    gdb_test "" ".*reakpoint $bkptno_numopt_re, main .*${srcfile}.*" "start the second inf"
>  }
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> index cbccba19d12..3c079facced 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> @@ -27,7 +27,7 @@ if {[build_executable "failed to build" $testfile $srcfile {debug}]} {
>  # child.  Can be either "kill", "detach", or "exit" (to continue it to
>  # normal exit).
>  proc do_test {dispose} {
> -    global binfile
> +    global binfile bkptno_numopt_re
>  
> 
>      clean_restart $binfile
>  
> 
> @@ -77,7 +77,7 @@ proc do_test {dispose} {
>      #  Command aborted.
>      #  (gdb)
>      #
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker .*" \
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker .*" \
>  	"continue in inferior 1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi.exp b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> index e4329dca6c2..0fc1bee762f 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> @@ -84,11 +84,11 @@ if [skip_hw_watchpoint_multi_tests] {
>  	"Hardware access \\(read/write\\) watchpoint \[0-9\]+: c\r\n\r\nOld value = 0\r\nNew value = 3\r\n.*" \
>  	"catch c on inferior 2"
>  
> 
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 2"
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 2"
>  
> 
>      gdb_test "inferior 1" "witching to inferior 1 .*" "switch back to inferior 1 again"
>  
> 
>      gdb_test "continue" "Hardware access \\(read/write\\) watchpoint \[0-9\]+: b\r\n\r\nOld value = 0\r\nNew value = 2\r\n.*" "catch b on inferior 1"
>  }
>  
> 
> -gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 1"
> +gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 1"
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 402450152ac..5e4c793598e 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -227,6 +227,14 @@ set inferior_exited_re "(?:\\\[Inferior \[0-9\]+ \\(\[^\n\r\]*\\) exited)"
>  # E.g., $1, $2, etc.
>  set valnum_re "\\\$$decimal"
>  
> 
> +# A regular expression that matches a breakpoint hit with a breakpoint
> +# having several code locations.
> +set bkptno_num_re "$decimal\\.$decimal"
> +
> +# A regular expression that matches a breakpoint hit
> +# with one or several code locations.
> +set bkptno_numopt_re "($decimal\\.$decimal|$decimal)"
> +
>  ### Only procedures should come after this point.
>  
> 
>  #
> @@ -662,6 +670,7 @@ proc gdb_breakpoint { linespec args } {
>  
> 
>  proc runto { linespec args } {
>      global gdb_prompt
> +    global bkptno_numopt_re
>      global decimal
>  
> 
>      delete_breakpoints
> @@ -699,7 +708,7 @@ proc runto { linespec args } {
>  	    }
>  	    return 1
>  	}
> -	-re "Breakpoint \[0-9\]*, \[0-9xa-f\]* in .*$gdb_prompt $" { 
> +	-re "Breakpoint $bkptno_numopt_re, \[0-9xa-f\]* in .*$gdb_prompt $" {
>  	    if { $print_pass } {
>  		pass $test_name
>  	    }
> diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
> index e578a7e6f9b..ea66fdcabf8 100644
> --- a/gdb/testsuite/lib/mi-support.exp
> +++ b/gdb/testsuite/lib/mi-support.exp
> @@ -1195,11 +1195,11 @@ proc mi_detect_async {} {
>  # filename of a file without debug info.  ARGS should not include [] the
>  # list of argument is enclosed in, and other regular expressions should
>  # not include quotes.
> -# If EXTRA is a list of one element, it's the regular expression
> +# EXTRA can be a list of one, two or three elements.
> +# The first element is the regular expression
>  # for output expected right after *stopped, and before GDB prompt.
> -# If EXTRA is a list of two elements, the first element is for
> -# output right after *stopped, and the second element is output
> -# right after reason field.  The regex after reason should not include
> +# The third element is the regulation expression for the locno
> +# right after bkptno field.  The locno regex should not include
>  # the comma separating it from the following fields.
>  #
>  # When we fail to match output at all, -1 is returned.  If FILE does
> @@ -1224,7 +1224,14 @@ proc mi_expect_stop { reason func args file line extra test } {
>  
> 
>      set after_stopped ""
>      set after_reason ""
> -    if { [llength $extra] == 2 } {
> +    set locno ""
> +    if { [llength $extra] == 3 } {
> +	set after_stopped [lindex $extra 0]
> +	set after_reason [lindex $extra 1]
> +	set after_reason "${after_reason},"
> +	set locno [lindex $extra 2]
> +	set locno "${locno},"
> +    } elseif { [llength $extra] == 2 } {
>  	set after_stopped [lindex $extra 0]
>  	set after_reason [lindex $extra 1]
>  	set after_reason "${after_reason},"
> @@ -1298,10 +1305,12 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set ebn ""
>      if { $reason == "breakpoint-hit" } {
>  	set bn {bkptno="[0-9]+",}
> +	set bn "${bn}${locno}"
>      } elseif { $reason == "solib-event" } {
>  	set bn ".*"
>      } elseif { $reason == "exception-caught" } {
>  	set ebn {bkptno="[0-9]+",}
> +	set ebn "${ebn}${locno}"
>  	set bn ".*"
>  	set reason "breakpoint-hit"
>      }
> @@ -1315,6 +1324,7 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set a $after_reason
>  
> 
>      verbose -log "mi_expect_stop: expecting: \\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
> +
>      gdb_expect {
>  	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
>  	    pass "$test"



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-06-06  9:45 [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno Philippe Waroquiers
                   ` (3 preceding siblings ...)
  2022-06-26 17:27 ` Philippe Waroquiers
@ 2022-07-22 16:57 ` Philippe Waroquiers
  2022-07-29 18:56 ` Philippe Waroquiers
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Philippe Waroquiers @ 2022-07-22 16:57 UTC (permalink / raw)
  To: gdb-patches


Ping ^ 4
(Eli reviewed the doc, Keith did a first review)

Thanks
Philippe



On Mon, 2022-06-06 at 11:45 +0200, Philippe Waroquiers wrote:
> Before this patch, when a breakpoint that has multiple locations is reached,
> GDB printed:
>   Thread 1 "zeoes" hit Breakpoint 1, some_func () at somefunc1.c:5
> 
> This patch changes the message so that bkpt_print_id prints the precise
> encountered breakpoint:
>   Thread 1 "zeoes" hit Breakpoint 1.2, some_func () at somefunc1.c:5
> 
> In mi mode, bkpt_print_id also (optionally) prints a new table field "locno":
>   locno is printed when the breakpoint has more than one location.
> Note that according to the GDB user manual node 'GDB/MI Development and Front
> Ends', it is ok to add new fields without changing the MI version.
> 
> Also, when a breakpoint is reached, the convenience variables
> $bkptno and $locno are set to the encountered breakpoint number
> and location number.
> 
> $bkptno and $locno can a.o. be used in the command list of a breakpoint,
> to disable the specific encountered breakpoint, e.g.
>    disable $bkptno.$locno
> 
> In case the breakpoint has only one location, $locno is still set to
> the value 1, so as to allow a command such as:
>   disable $bkptno.$locno
> even when the breakpoint has only one location.
> 
> This also fixes a strange behaviour: when a breakpoint X has only
> one location,
>   enable|disable X.1
> is accepted but transforms the breakpoint in a multiple locations
> breakpoint having only one location.
> 
> The changes in RFA v3 handle the additional comments of Eli:
>  GDB/NEW:
>   - Use max 80-column
>   - Use 'code location' instead of 'location'.
>   - Fix typo $bkpno
>   - Ensure that disable $bkptno and disable $bkptno.$locno have
>     each their explanation inthe example
>   - Reworded the 'breakpoint-hit' paragraph.
>  gdb.texinfo:
>   - Use 'code location' instead of 'location'.
>   - Add a note to clarify the distinction between $bkptno and $bpnum.
>   - Use @kbd instead of examples with only one command.
> 
> Compared to RFA v1, the changes in v2 handle the comments given by
> Keith Seitz and Eli Zaretskii:
>   - Use %s for the result of paddress
>   - Use bkptno_numopt_re instead of 2 different -re cases
>   - use C@t{++}
>   - Add index entries for $bkptno and $locno
>   - Added an example for "locno" in the mi interface
>   - Added examples in the Break command manual.
> ---
>  gdb/NEWS                                      | 21 +++++
>  gdb/ada-lang.c                                |  2 +-
>  gdb/break-catch-syscall.c                     |  2 +-
>  gdb/break-catch-throw.c                       |  2 +-
>  gdb/breakpoint.c                              | 93 +++++++++++++++----
>  gdb/breakpoint.h                              | 14 +++
>  gdb/doc/gdb.texinfo                           | 83 ++++++++++++++++-
>  gdb/infrun.c                                  | 16 +++-
>  gdb/testsuite/gdb.ada/bp_inlined_func.exp     |  2 +-
>  gdb/testsuite/gdb.ada/operator_bp.exp         |  4 +-
>  .../gdb.base/condbreak-multi-context.exp      |  8 +-
>  gdb/testsuite/gdb.base/ctxobj.exp             | 26 ++++--
>  gdb/testsuite/gdb.base/ena-dis-br.exp         | 41 ++++----
>  gdb/testsuite/gdb.base/foll-exec-mode.exp     |  6 +-
>  gdb/testsuite/gdb.base/pie-fork.exp           |  4 +-
>  gdb/testsuite/gdb.base/step-over-exit.exp     |  4 +-
>  gdb/testsuite/gdb.cp/mb-inline.exp            |  4 +-
>  gdb/testsuite/gdb.cp/mb-templates.exp         |  6 +-
>  gdb/testsuite/gdb.cp/ovldbreak.exp            |  6 +-
>  gdb/testsuite/gdb.gdb/python-helper.exp       |  4 +-
>  .../gdb.mi/interrupt-thread-group.exp         |  2 +-
>  .../gdb.mi/user-selected-context-sync.exp     | 35 +++++--
>  gdb/testsuite/gdb.multi/multi-arch-exec.exp   |  3 +-
>  .../gdb.multi/run-only-second-inf.exp         |  2 +-
>  .../gdb.multi/watchpoint-multi-exit.exp       |  4 +-
>  gdb/testsuite/gdb.multi/watchpoint-multi.exp  |  4 +-
>  gdb/testsuite/lib/gdb.exp                     | 11 ++-
>  gdb/testsuite/lib/mi-support.exp              | 20 +++-
>  28 files changed, 335 insertions(+), 94 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 960f90b4387..a5602deee2b 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -34,6 +34,21 @@
>       whitespace from each line before using the string as the help
>       output.
>  
> 
> +* When a breakpoint with multiple code locations is hit, GDB now prints
> +  the code location using the syntax <breakpoint_number>.<location_number>
> +  such as in:
> +     Thread 1 "zeoes" hit Breakpoint 2.3, some_func () at zeoes.c:8
> +
> +* When a breakpoint is hit, GDB now sets the convenience variables $bkptno and
> +  $locno to the hit breakpoint number and code location number.
> +  This allows to disable the last hit breakpoint using
> +     (gdb) disable $bkptno
> +   or disable only the specific breakpoint code location using
> +     (gdb) disable $bkptno.$locno
> +  These commands can be used inside the command list of a breakpoint to
> +  automatically disable the just encountered breakpoint (or the just
> +  encountered specific breakpoint code location).
> +
>  * New commands
>  
> 
>  maintenance set ignore-prologue-end-flag on|off
> @@ -50,6 +65,12 @@ maintenance info line-table
>    entry corresponds to an address where a breakpoint should be placed
>    to be at the first instruction past a function's prologue.
>  
> 
> +* MI changes
> +
> + ** The async record stating the stopped reason 'breakpoint-hit' now
> +    contains an optional field locno giving the code location number
> +    when the breakpoint has multiple code locations.
> +
>  * Python API
>  
> 
>    ** New function gdb.format_address(ADDRESS, PROGSPACE, ARCHITECTURE),
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 6ab01fd27d4..bbae76f39ac 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -12348,7 +12348,7 @@ ada_catchpoint::print_it (const bpstat *bs) const
>  
> 
>    uiout->text (disposition == disp_del
>  	       ? "\nTemporary catchpoint " : "\nCatchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    /* ada_exception_name_addr relies on the selected frame being the
> diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
> index 06d48466de7..82229de33f7 100644
> --- a/gdb/break-catch-syscall.c
> +++ b/gdb/break-catch-syscall.c
> @@ -218,7 +218,7 @@ syscall_catchpoint::print_it (const bpstat *bs) const
>  						: EXEC_ASYNC_SYSCALL_RETURN));
>        uiout->field_string ("disp", bpdisp_text (b->disposition));
>      }
> -  uiout->field_signed ("bkptno", b->number);
> +  print_num_locno (bs, uiout);
>  
> 
>    if (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY)
>      uiout->text (" (call to syscall ");
> diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
> index 66cf80be1c5..5b6f5d9eca1 100644
> --- a/gdb/break-catch-throw.c
> +++ b/gdb/break-catch-throw.c
> @@ -257,7 +257,7 @@ exception_catchpoint::print_it (const bpstat *bs) const
>    bp_temp = disposition == disp_del;
>    uiout->text (bp_temp ? "Temporary catchpoint "
>  		       : "Catchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text ((kind == EX_EVENT_THROW ? " (exception thrown), "
>  		: (kind == EX_EVENT_CATCH ? " (exception caught), "
>  		   : " (exception rethrown), ")));
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index ed932a19ed7..c89c800f32f 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -820,6 +820,19 @@ get_breakpoint (int num)
>    return nullptr;
>  }
>  
> 
> +/* Return TRUE if NUM refer to an existing breakpoint that has
> +   multiple code locations.  */
> +
> +static bool
> +has_multiple_locations (int num)
> +{
> +  for (breakpoint *b : all_breakpoints ())
> +    if (b->number == num)
> +      return b->loc != nullptr && b->loc->next != nullptr;
> +
> +  return false;
> +}
> +
>  \f
>  
> 
>  /* Mark locations as "conditions have changed" in case the target supports
> @@ -4451,15 +4464,7 @@ bpstat_explains_signal (bpstat *bsp, enum gdb_signal sig)
>    return false;
>  }
>  
> 
> -/* Put in *NUM the breakpoint number of the first breakpoint we are
> -   stopped at.  *BSP upon return is a bpstat which points to the
> -   remaining breakpoints stopped at (but which is not guaranteed to be
> -   good for anything but further calls to bpstat_num).
> -
> -   Return 0 if passed a bpstat which does not indicate any breakpoints.
> -   Return -1 if stopped at a breakpoint that has been deleted since
> -   we set it.
> -   Return 1 otherwise.  */
> +/* See breakpoint.h.  */
>  
> 
>  int
>  bpstat_num (bpstat **bsp, int *num)
> @@ -4481,6 +4486,57 @@ bpstat_num (bpstat **bsp, int *num)
>    return 1;
>  }
>  
> 
> +/* See breakpoint.h  */
> +
> +int
> +bpstat_locno (const bpstat *bs)
> +{
> +  const struct breakpoint *b = bs->breakpoint_at;
> +  const struct bp_location *bl = bs->bp_location_at.get ();
> +
> +  int locno = 0;
> +
> +  if (b != nullptr && b->loc->next != nullptr)
> +    {
> +      const bp_location *bl_i;
> +
> +      for (bl_i = b->loc;
> +	   bl_i != bl && bl_i->next != nullptr;
> +	   bl_i = bl_i->next)
> +	locno++;
> +
> +      if (bl_i == bl)
> +	locno++;
> +      else
> +	{
> +	  warning (_("location number not found for breakpoint %d address %s."),
> +		   b->number, paddress (bl->gdbarch, bl->address));
> +	  locno = 0;
> +	}
> +    }
> +
> +  return locno;
> +}
> +
> +/* See breakpoint.h.  */
> +
> +void
> +print_num_locno (const bpstat *bs, struct ui_out *uiout)
> +{
> +  struct breakpoint *b = bs->breakpoint_at;
> +
> +  if (b == nullptr)
> +    uiout->text (_("deleted breakpoint"));
> +  else
> +    {
> +      uiout->field_signed ("bkptno", b->number);
> +
> +      int locno = bpstat_locno (bs);
> +      if (locno != 0)
> +	uiout->message (".%pF", signed_field ("locno", locno));
> +    }
> +}
> +
>  /* See breakpoint.h.  */
>  
> 
>  void
> @@ -9176,7 +9232,7 @@ ranged_breakpoint::print_it (const bpstat *bs) const
>  		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
> @@ -11610,12 +11666,13 @@ ordinary_breakpoint::print_it (const bpstat *bs) const
>  			   async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> +
>    if (bp_temp)
> -    uiout->message ("Temporary breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Temporary breakpoint ");
>    else
> -    uiout->message ("Breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Breakpoint ");
> +  print_num_locno (bs, uiout);
> +  uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
>  }
> @@ -13220,9 +13277,13 @@ enable_disable_command (const char *args, int from_tty, bool enable)
>  	  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)
> +	      && (bp_loc_range.first == 0
> +		  || (bp_loc_range.first == 1
> +		      && bp_num_range.first == bp_num_range.second
> +		      && !has_multiple_locations (bp_num_range.first))))
>  	    {
> -	      /* Handle breakpoint ids with formats 'x' or 'x-z'.  */
> +	      /* Handle breakpoint ids with formats 'x' or 'x-z'
> +		 or 'y.1' where y has only one code location.  */
>  	      map_breakpoint_number_range (bp_num_range,
>  					   enable
>  					   ? enable_breakpoint
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 566f1285e46..96d61ef5427 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -1231,6 +1231,20 @@ extern enum print_stop_action bpstat_print (bpstat *, int);
>     Return 1 otherwise.  */
>  extern int bpstat_num (bpstat **, int *);
>  
> 
> +/* If BS indicates a breakpoint and this breakpoint has several code locations,
> +   return the location number of BS, otherwise return 0.  */
> +
> +extern int bpstat_locno (const bpstat *bs);
> +
> +/* Print BS breakpoint number optionally followed by a . and breakpoint locno.
> +
> +   For a breakpoint with only one code location, outputs the signed field
> +   "bkptno" breakpoint number of BS (as returned by bpstat_num).
> +   If BS has several code locations, outputs a '.' character followed by
> +   the signed field "locno" (as returned by bpstat_locno).  */
> +
> +extern void print_num_locno (const bpstat *bs, struct ui_out *);
> +
>  /* Perform actions associated with the stopped inferior.  Actually, we
>     just use this for breakpoint commands.  Perhaps other actions will
>     go here later, but this is executed at a late time (from the
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 434add3a663..391b81f8863 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -4338,9 +4338,65 @@ are operated on.
>  @cindex latest breakpoint
>  Breakpoints are set with the @code{break} command (abbreviated
>  @code{b}).  The debugger convenience variable @samp{$bpnum} records the
> -number of the breakpoint you've set most recently; see @ref{Convenience
> -Vars,, Convenience Variables}, for a discussion of what you can do with
> -convenience variables.
> +number of the breakpoint you've set most recently:
> +@smallexample
> +(gdb) b main
> +Breakpoint 1 at 0x11c6: file zeoes.c, line 24.
> +(gdb) p $bpnum
> +$1 = 1
> +@end smallexample
> +
> +A breakpoint may be mapped to multiple code locations for example with
> +inlined functions, Ada generics, C@t{++} templates or overloaded function names.
> +@value{GDBN} then indicates the number of code locations in the breakpoint
> +command output:
> +@smallexample
> +(gdb) b some_func
> +Breakpoint 2 at 0x1179: some_func. (3 locations)
> +(gdb) p $bpnum
> +$2 = 2
> +(gdb)
> +@end smallexample
> +
> +@vindex $bkptno@r{, convenience variable}
> +@vindex $locno@r{, convenience variable}
> +When your program stops on a breakpoint, the convenience variables
> +@samp{$bkptno} and @samp{$locno} are respectively set to the number of
> +the encountered breakpoint and the number of the breakpoint's code location:
> +@smallexample
> +Thread 1 "zeoes" hit Breakpoint 2.1, some_func () at zeoes.c:8
> +8	  printf("some func\n");
> +(gdb) p $bkptno
> +$5 = 2
> +(gdb) p $locno
> +$6 = 1
> +(gdb)
> +@end smallexample
> +
> +Note that @samp{$bkptno} and @samp{$bpnum} are not equivalent:
> +@samp{$bkptno} is set to the breakpoint number @b{last hit}, while
> +@samp{$bpnum} is set to the breakpoint number @b{last set}.
> +
> +
> +If the encountered breakpoint has only one code location, @samp{$locno} is set
> +to 1:
> +@smallexample
> +Breakpoint 1, main (argc=1, argv=0x7fffffffe018) at zeoes.c:24
> +24	  if (argc > 1)
> +(gdb) p $bkptno
> +$3 = 1
> +(gdb) p $locno
> +$4 = 1
> +(gdb)
> +@end smallexample
> +
> +The @samp{$bkptno} and @samp{$locno} variables can typically be used
> +in a breakpoint command list.
> +(@pxref{Break Commands, ,Breakpoint Command Lists}). For example, as
> +part of the breakpoint command list, you can disable completely the
> +encountered breakpoint using @samp{disable $bkptno} or disable the
> +specific encountered breakpoint location using @samp{disable
> +$bkptno.$locno}.
>  
> 
>  @table @code
>  @item break @var{locspec}
> @@ -5739,6 +5795,13 @@ Expressions}).
>  Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
>  disabled within a @var{command-list}.
>  
> 
> +Inside a command list, you can use the command
> +@kbd{disable $bkptno} to disable the encountered breakpoint.
> +
> +If your breakpoint has several code locations, the command
> +@kbd{disable $bkptno.$locno} will disable the specific breakpoint code
> +location encountered.
> +
>  You can use breakpoint commands to start your program up again.  Simply
>  use the @code{continue} command, or @code{step}, or any other command
>  that resumes execution.
> @@ -32570,6 +32633,20 @@ line="13",arch="i386:x86_64"@}
>  (gdb)
>  @end smallexample
>  
> 
> +For a @samp{breakpoint-hit} stopped reason, when the breakpoint
> +encountered has multiple locations, the field @samp{bkptno} is
> +followed by the field @samp{locno}.
> +
> +@smallexample
> +-exec-continue
> +^running
> +(gdb)
> +@@Hello world
> +*stopped,reason="breakpoint-hit",disp="keep",bkptno="2",locno="3",frame=@{
> +func="foo",args=[],file="hello.c",fullname="/home/foo/bar/hello.c",
> +line="13",arch="i386:x86_64"@}
> +(gdb)
> +@end smallexample
>  
> 
>  @subheading The @code{-exec-finish} Command
>  @findex -exec-finish
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 02c98b50c8c..e5ad062a914 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -8494,7 +8494,21 @@ print_stop_location (const target_waitstatus &ws)
>       LOCATION: Print only location
>       SRC_AND_LOC: Print location and source line.  */
>    if (do_frame_printing)
> -    print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    {
> +      if (tp->control.stop_bpstat != nullptr)
> +	{
> +	  const struct breakpoint *b = tp->control.stop_bpstat->breakpoint_at;
> +
> +	  if (b != nullptr)
> +	    {
> +	      int locno = bpstat_locno (tp->control.stop_bpstat);
> +	      set_internalvar_integer (lookup_internalvar ("bkptno"), b->number);
> +	      set_internalvar_integer (lookup_internalvar ("locno"),
> +				       (locno > 0 ? locno : 1));
> +	    }
> +	}
> +      print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    }
>  }
>  
> 
>  /* See infrun.h.  */
> diff --git a/gdb/testsuite/gdb.ada/bp_inlined_func.exp b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> index 076e8c2425f..3f94c163819 100644
> --- a/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> +++ b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> @@ -42,7 +42,7 @@ gdb_test "break read_small" \
>  for {set i 0} {$i < 4} {incr i} {
>      with_test_prefix "iteration $i" {
>  	gdb_test "continue" \
> -	    "Breakpoint $decimal, b\\.read_small \\(\\).*" \
> +	    "Breakpoint $bkptno_num_re, b\\.read_small \\(\\).*" \
>  	    "stopped in read_small"
>      }
>  }
> diff --git a/gdb/testsuite/gdb.ada/operator_bp.exp b/gdb/testsuite/gdb.ada/operator_bp.exp
> index 655e7af479f..e3928419ed6 100644
> --- a/gdb/testsuite/gdb.ada/operator_bp.exp
> +++ b/gdb/testsuite/gdb.ada/operator_bp.exp
> @@ -56,7 +56,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to \"$op\""
>  }
>  
> 
> @@ -86,7 +86,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to ops.\"$op\""
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> index b540df973a3..742315178e3 100644
> --- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> +++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> @@ -140,11 +140,11 @@ with_test_prefix "scenario 1" {
>      gdb_run_cmd
>  
> 
>      # Check our conditional breakpoints.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> @@ -208,11 +208,11 @@ with_test_prefix "scenario 2" {
>      gdb_run_cmd
>  
> 
>      # Check that we hit enabled locations only.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> diff --git a/gdb/testsuite/gdb.base/ctxobj.exp b/gdb/testsuite/gdb.base/ctxobj.exp
> index 9c010f54d79..0b589a7d6e6 100644
> --- a/gdb/testsuite/gdb.base/ctxobj.exp
> +++ b/gdb/testsuite/gdb.base/ctxobj.exp
> @@ -67,9 +67,16 @@ gdb_test "break ctxobj-f.c:$bp_location" \
>           "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
>           "break in get_version functions"
>  
> 
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_1 \\(\\).*" \
> -         "continue to get_version_1"
> +global expect_out
> +set test "continue to get_version_1"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_1 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  # Try printing "this_version_num".  There are two global variables
>  # with that name, and some systems such as GNU/Linux merge them
> @@ -100,10 +107,15 @@ gdb_test "print this_version_num == v" \
>          "print libctxobj1's this_version_num from symtab"
>  
> 
>  # Do the same, but from get_version_2.
> -
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_2 \\(\\).*" \
> -         "continue to get_version_2"
> +set test "continue to get_version_2"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_2 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  gdb_test "print this_version_num == v" \
>           " = 1" \
> diff --git a/gdb/testsuite/gdb.base/ena-dis-br.exp b/gdb/testsuite/gdb.base/ena-dis-br.exp
> index 24925cf7185..04b3f134b44 100644
> --- a/gdb/testsuite/gdb.base/ena-dis-br.exp
> +++ b/gdb/testsuite/gdb.base/ena-dis-br.exp
> @@ -67,14 +67,21 @@ gdb_test "info break $bp" \
>  # See the comments in condbreak.exp for "run until breakpoint at
>  # marker1" for an explanation of the xfail below.
>  set test "continue to break marker1"
> +set bpno 0
>  gdb_test_multiple "continue" "$test" {
> -    -re "Breakpoint \[0-9\]*, marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	pass "$test"
>      }
> -    -re "Breakpoint \[0-9\]*, $hex in marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), $hex in marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	xfail "$test"
>      }
>  }
> +# Verify the $bkptno convenience variable is equal to the hit bpno.
> +gdb_test "print \$bkptno" " = $bpno" "$test \$bkptno is $bpno"
> +# Verify the $locno is 1, as there is only one code location.
> +gdb_test "print \$locno" " = 1" "$test \$locno is 1"
>  
> 
>  gdb_test_no_output "delete $bp" "delete break marker1"
>  
> 
> @@ -359,7 +366,8 @@ with_test_prefix "4th breakpoint" {
>  }
>  
> 
>  # Perform tests for disable/enable commands on multiple
> -# locations and breakpoints.
> +# code locations and breakpoints.  If a breakpoint has only one code location,
> +# enable/disable num  and enable/disable num.1 should be equivalent.
>  #
>  # WHAT - the command to test (disable/enable).
>  #
> @@ -372,7 +380,7 @@ proc test_ena_dis_br { what } {
>      global b3
>      global b4
>      global gdb_prompt
> -    
> +
>      # OPPOS    - the command opposite to WHAT.
>      # WHAT_RES - whether breakpoints are expected to end
>      #            up enabled or disabled.
> @@ -395,13 +403,13 @@ proc test_ena_dis_br { what } {
>  	set p2 "pass"
>      }
>  
> 
> -    # Now enable(disable) $b.1 $b2.1.
> +    # Now enable(disable) $b1.1 $b2.1.
>      gdb_test_no_output "$what $b1.1 $b2.1" "$what \$b1.1 \$b2.1"
>      set test1 "${what}d \$b1.1 and \$b2.1"
>  
> 
>      # Now $b1.1 and $b2.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -       -re "(${b1}.1)(\[^\n\r\]*)( n.*)(${b2}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +       -re "(${b1})(\[^\n\r\]*)( n.*)(${b2})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> @@ -420,19 +428,16 @@ proc test_ena_dis_br { what } {
>         "${what}d \$b1"
>  
> 
>      gdb_test_no_output "$oppos $b3" "$oppos \$b3"
> +    # Now $b4 $b3 should be enabled(disabled)
> +    set test1 "${what}d \$b4 and \$b3"
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $oppos_res.*).*(${b4})(\[^\n\r\]*)( $oppos_res.*)" "$test1"
> +
>      gdb_test_no_output "$what $b4 $b3.1" "$what \$b4 \$b3.1"
> -    set test1 "${what}d \$b4 and \$b3.1,remain ${oppos}d \$b3"
> +    set test1 "${what}d \$b4 and \$b3.1, changing \$b3"
> +
> +    # Now $b4 $b3 should be enabled(disabled)
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $what_res.*).*(${b4})(\[^\n\r\]*)( $what_res.*)" "$test1"
>  
> 
> -    # Now $b4 $b3.1 should be enabled(disabled) and
> -    # $b3 should remain disabled(enabled).
> -    gdb_test_multiple "info break" "$test1" {
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b3}.1)(\[^\n\r\]*)( n.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p1 "$test1"
> -       }
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p2 "$test1"
> -       }
> -    }
>  
> 
>      # Now enable(disable) '$b4.1 fooobaar'.  This should error on
>      # fooobaar.
> @@ -443,7 +448,7 @@ proc test_ena_dis_br { what } {
>  
> 
>      # $b4.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -        -re "(${b4}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +        -re "(${b4})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.base/foll-exec-mode.exp b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> index 918f3e4fd5f..cb6d975a767 100644
> --- a/gdb/testsuite/gdb.base/foll-exec-mode.exp
> +++ b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> @@ -99,7 +99,7 @@ proc do_catch_exec_test { } {
>  # before re-running.
>  
> 
>  proc do_follow_exec_mode_tests { mode cmd infswitch } {
> -    global binfile srcfile srcfile2 testfile testfile2
> +    global binfile srcfile srcfile2 testfile testfile2 bkptno_numopt_re
>      global gdb_prompt
>  
> 
>      with_test_prefix "$mode,$cmd,$infswitch" {
> @@ -125,7 +125,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  	# Set up the output we expect to see after we execute past the exec.
>  	#
>  	set execd_line [gdb_get_line_number "after-exec" $srcfile2]
> -	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint .,.*${srcfile2}:${execd_line}.*$gdb_prompt $"
> +	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint ${bkptno_numopt_re},.*${srcfile2}:${execd_line}.*$gdb_prompt $"
>  
> 
>  	# Set a breakpoint after the exec call if we aren't single-stepping
>  	# past it.
> @@ -189,7 +189,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  		send_gdb "y\n"
>  		exp_continue
>  	    }
> -	    -re "Starting program: .*$expected_inf.*Breakpoint .,.*\r\n$gdb_prompt $" {
> +	    -re "Starting program: .*$expected_inf.*Breakpoint $bkptno_numopt_re,.*\r\n$gdb_prompt $" {
>  		pass $test
>  	    }
>  	}
> diff --git a/gdb/testsuite/gdb.base/pie-fork.exp b/gdb/testsuite/gdb.base/pie-fork.exp
> index efc357d39a2..19e9d3a5537 100644
> --- a/gdb/testsuite/gdb.base/pie-fork.exp
> +++ b/gdb/testsuite/gdb.base/pie-fork.exp
> @@ -54,10 +54,10 @@ proc_with_prefix test_detach_on_fork_follow_child {} {
>  proc_with_prefix test_no_detach_on_fork {} {
>      setup_test "off"
>  
> 
> -    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2.1, break_here.*" \
>  	     "continue from thread 1.1"
>      gdb_test "thread 2.1"
> -    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2.2, break_here.*" \
>  	     "continue from thread 2.1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/step-over-exit.exp b/gdb/testsuite/gdb.base/step-over-exit.exp
> index f8bd99980fe..575319c564c 100644
> --- a/gdb/testsuite/gdb.base/step-over-exit.exp
> +++ b/gdb/testsuite/gdb.base/step-over-exit.exp
> @@ -91,7 +91,7 @@ delete_breakpoints
>  
> 
>  gdb_test "break marker"
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_num_re, .*" \
>      "continue to marker, first time"
>  
> 
>  # Step 2, create a breakpoint which evaluates false, and force it
> @@ -120,5 +120,5 @@ gdb_test "inferior 1" ".*Switching to inferior 1.*" \
>  # Switch back to the parent process, continue to the marker to
>  # test GDBserver's state is still correct.
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_numopt_re, .*" \
>      "continue to marker, second time"
> diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
> index 47a2a5dcb7c..fa098602c31 100644
> --- a/gdb/testsuite/gdb.cp/mb-inline.exp
> +++ b/gdb/testsuite/gdb.cp/mb-inline.exp
> @@ -46,7 +46,7 @@ gdb_test "info break" \
>      "\[\r\n\]1\.1.* y .* at .*$hdrfile:$bp_location.*\[\r\n\]1\.2.* y .* at .*$hdrfile:$bp_location.*"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo \\(i=1\\).*" \
> @@ -59,7 +59,7 @@ gdb_test "continue" \
>  gdb_test_no_output "disable 1.2" "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
>  
> 
>  gdb_test_multiple "info break" "disabled breakpoint 1.2" {
>      -re "1\.2.* n .* at .*$hdrfile:$bp_location.*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
> index 6c988e7335e..0c0d46fcb7a 100644
> --- a/gdb/testsuite/gdb.cp/mb-templates.exp
> +++ b/gdb/testsuite/gdb.cp/mb-templates.exp
> @@ -42,7 +42,7 @@ gdb_run_cmd
>  
> 
>  set test "initial condition: run to breakpoint"
>  gdb_test_multiple "" $test {
> -    -re "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
> +    -re "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
>  	pass $test
>  	break
>      }
> @@ -67,7 +67,7 @@ gdb_test_no_output {condition $bpnum i==1} \
>      "separate condition: set condition"
>      
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo<double> \\(i=1\\).*" \
> @@ -79,7 +79,7 @@ gdb_test "continue" \
>  gdb_test_no_output {disable $bpnum.1} "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
>  
> 
>  # Try disabling entire breakpoint
>  gdb_test_no_output {enable $bpnum.1} "disabling location: enable"
> diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
> index 06adf82ecbb..0ed9eae055b 100644
> --- a/gdb/testsuite/gdb.cp/ovldbreak.exp
> +++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
> @@ -380,7 +380,7 @@ gdb_test "info break" $bptable "breakpoint info (after setting on all)"
>  
> 
>  # Run through each breakpoint.
>  proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
> -    global gdb_prompt hex decimal srcfile
> +    global gdb_prompt hex decimal srcfile bkptno_num_re
>  
> 
>      if {$argument == ""} {
>          set actuals ""
> @@ -398,11 +398,11 @@ proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
>      }
>  
> 
>      gdb_test_multiple "continue" "continue to bp overloaded : $argtype" {
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              pass "continue to bp overloaded : $argtype"
>          }
>  
> 
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              if $might_kfail {
>                  kfail "c++/8130" "continue to bp overloaded : $argtype"
>              } else {
> diff --git a/gdb/testsuite/gdb.gdb/python-helper.exp b/gdb/testsuite/gdb.gdb/python-helper.exp
> index 6db8bf0df50..30eb6038f3a 100644
> --- a/gdb/testsuite/gdb.gdb/python-helper.exp
> +++ b/gdb/testsuite/gdb.gdb/python-helper.exp
> @@ -49,7 +49,7 @@ gdb_exit
>  # The main test.  This is called by the self-test framework once GDB
>  # has been started on a copy of itself.
>  proc test_python_helper {} {
> -    global py_helper_script decimal hex gdb_prompt
> +    global py_helper_script decimal hex gdb_prompt bkptno_numopt_re
>      global inferior_spawn_id
>  
> 
>      # Source the python helper script.  This script registers the
> @@ -233,7 +233,7 @@ proc test_python_helper {} {
>      # GDB stopping at the value_print breakpoint again.
>      send_inferior "ptype global_c\n"
>      gdb_test_multiple "" "hit breakpoint in outer gdb again" {
> -	-re "Breakpoint $decimal, c_print_type .*\\(outer-gdb\\) $" {
> +	-re "Breakpoint $bkptno_numopt_re, c_print_type .*\\(outer-gdb\\) $" {
>  	    pass $gdb_test_name
>  	}
>      }
> diff --git a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> index 19ccbe85e04..c080955049c 100644
> --- a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> +++ b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> @@ -69,7 +69,7 @@ if { $use_second_inferior } {
>  	"\\^running.*" \
>  	"run inferior 2"
>  
> 
> -    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\""} \
> +    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\"" "locno=\"[0-9]+\""} \
>  	"inferior i2 stops at all_threads_started"
>  
> 
>      mi_send_resuming_command "exec-continue --thread-group i2" \
> diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> index d78c96ddef1..9eec083068b 100644
> --- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> +++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> @@ -307,8 +307,13 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  	    # Consume MI event output.
>  	    with_spawn_id $mi_spawn_id {
> -		mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> -		    "$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		if { $inf == 1 } {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		} else {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} "stop at breakpoint in main"
> +		}
>  	    }
>  
> 
>  	    if { $mode == "all-stop" } {
> @@ -330,9 +335,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		    # Consume MI output.
>  		    with_spawn_id $mi_spawn_id {
> -			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			    "thread $inf.$thread stops MI"
> +			if { $inf == 1} {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +				"thread $inf.$thread stops MI"
> +			} else {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +				"thread $inf.$thread stops MI"
> +			}
>  		    }
>  		}
>  
> 
> @@ -359,9 +370,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		# Consume MI output.
>  		with_spawn_id $mi_spawn_id {
> -		    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			"thread $inf.2 stops MI"
> +		    if { $inf == 1} {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +			    "thread $inf.2 stops MI"
> +		    } else {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +			    "thread $inf.2 stops MI"
> +		    }
>  		}
>  	    }
>  	}
> @@ -434,7 +451,7 @@ proc_with_prefix test_setup { mode } {
>  
> 
>  	with_spawn_id $mi_spawn_id {
>  	    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" "$decimal" \
> -		{"" "disp=\"del\""} "main stop"
> +		{"" "disp=\"del\"" "locno=\"[0-9]+\""} "main stop"
>  	}
>  
> 
>  	# Consume CLI output.
> diff --git a/gdb/testsuite/gdb.multi/multi-arch-exec.exp b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> index a1496fb5571..dfdb746c65e 100644
> --- a/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> +++ b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> @@ -148,6 +148,7 @@ proc build_executables { first_arch } {
>  }
>  
> 
>  proc do_test { first_arch mode selected_thread } {
> +        global bkptno_numopt_re
>  	set from_exec "$first_arch-multi-arch-exec"
>  
> 
>  	clean_restart ${from_exec}
> @@ -169,7 +170,7 @@ proc do_test { first_arch mode selected_thread } {
>  
> 
>  	# Test that GDB updates the target description / arch successfuly
>  	# after the exec.
> -	gdb_test "continue" "Breakpoint 2, main.*" "continue across exec that changes architecture"
> +	gdb_test "continue" "Breakpoint $bkptno_numopt_re, main.*" "continue across exec that changes architecture"
>  }
>  
> 
>  # Test both arch1=>arch2 and arch2=>arch1.
> diff --git a/gdb/testsuite/gdb.multi/run-only-second-inf.exp b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> index fec2575f904..b94689d0bfa 100644
> --- a/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> +++ b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> @@ -46,5 +46,5 @@ gdb_load $binfile
>  if {[gdb_start_cmd] < 0} {
>      fail "start the second inf"
>  } else {
> -    gdb_test "" ".*reakpoint ., main .*${srcfile}.*" "start the second inf"
> +    gdb_test "" ".*reakpoint $bkptno_numopt_re, main .*${srcfile}.*" "start the second inf"
>  }
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> index cbccba19d12..3c079facced 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> @@ -27,7 +27,7 @@ if {[build_executable "failed to build" $testfile $srcfile {debug}]} {
>  # child.  Can be either "kill", "detach", or "exit" (to continue it to
>  # normal exit).
>  proc do_test {dispose} {
> -    global binfile
> +    global binfile bkptno_numopt_re
>  
> 
>      clean_restart $binfile
>  
> 
> @@ -77,7 +77,7 @@ proc do_test {dispose} {
>      #  Command aborted.
>      #  (gdb)
>      #
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker .*" \
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker .*" \
>  	"continue in inferior 1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi.exp b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> index e4329dca6c2..0fc1bee762f 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> @@ -84,11 +84,11 @@ if [skip_hw_watchpoint_multi_tests] {
>  	"Hardware access \\(read/write\\) watchpoint \[0-9\]+: c\r\n\r\nOld value = 0\r\nNew value = 3\r\n.*" \
>  	"catch c on inferior 2"
>  
> 
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 2"
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 2"
>  
> 
>      gdb_test "inferior 1" "witching to inferior 1 .*" "switch back to inferior 1 again"
>  
> 
>      gdb_test "continue" "Hardware access \\(read/write\\) watchpoint \[0-9\]+: b\r\n\r\nOld value = 0\r\nNew value = 2\r\n.*" "catch b on inferior 1"
>  }
>  
> 
> -gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 1"
> +gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 1"
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 402450152ac..5e4c793598e 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -227,6 +227,14 @@ set inferior_exited_re "(?:\\\[Inferior \[0-9\]+ \\(\[^\n\r\]*\\) exited)"
>  # E.g., $1, $2, etc.
>  set valnum_re "\\\$$decimal"
>  
> 
> +# A regular expression that matches a breakpoint hit with a breakpoint
> +# having several code locations.
> +set bkptno_num_re "$decimal\\.$decimal"
> +
> +# A regular expression that matches a breakpoint hit
> +# with one or several code locations.
> +set bkptno_numopt_re "($decimal\\.$decimal|$decimal)"
> +
>  ### Only procedures should come after this point.
>  
> 
>  #
> @@ -662,6 +670,7 @@ proc gdb_breakpoint { linespec args } {
>  
> 
>  proc runto { linespec args } {
>      global gdb_prompt
> +    global bkptno_numopt_re
>      global decimal
>  
> 
>      delete_breakpoints
> @@ -699,7 +708,7 @@ proc runto { linespec args } {
>  	    }
>  	    return 1
>  	}
> -	-re "Breakpoint \[0-9\]*, \[0-9xa-f\]* in .*$gdb_prompt $" { 
> +	-re "Breakpoint $bkptno_numopt_re, \[0-9xa-f\]* in .*$gdb_prompt $" {
>  	    if { $print_pass } {
>  		pass $test_name
>  	    }
> diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
> index e578a7e6f9b..ea66fdcabf8 100644
> --- a/gdb/testsuite/lib/mi-support.exp
> +++ b/gdb/testsuite/lib/mi-support.exp
> @@ -1195,11 +1195,11 @@ proc mi_detect_async {} {
>  # filename of a file without debug info.  ARGS should not include [] the
>  # list of argument is enclosed in, and other regular expressions should
>  # not include quotes.
> -# If EXTRA is a list of one element, it's the regular expression
> +# EXTRA can be a list of one, two or three elements.
> +# The first element is the regular expression
>  # for output expected right after *stopped, and before GDB prompt.
> -# If EXTRA is a list of two elements, the first element is for
> -# output right after *stopped, and the second element is output
> -# right after reason field.  The regex after reason should not include
> +# The third element is the regulation expression for the locno
> +# right after bkptno field.  The locno regex should not include
>  # the comma separating it from the following fields.
>  #
>  # When we fail to match output at all, -1 is returned.  If FILE does
> @@ -1224,7 +1224,14 @@ proc mi_expect_stop { reason func args file line extra test } {
>  
> 
>      set after_stopped ""
>      set after_reason ""
> -    if { [llength $extra] == 2 } {
> +    set locno ""
> +    if { [llength $extra] == 3 } {
> +	set after_stopped [lindex $extra 0]
> +	set after_reason [lindex $extra 1]
> +	set after_reason "${after_reason},"
> +	set locno [lindex $extra 2]
> +	set locno "${locno},"
> +    } elseif { [llength $extra] == 2 } {
>  	set after_stopped [lindex $extra 0]
>  	set after_reason [lindex $extra 1]
>  	set after_reason "${after_reason},"
> @@ -1298,10 +1305,12 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set ebn ""
>      if { $reason == "breakpoint-hit" } {
>  	set bn {bkptno="[0-9]+",}
> +	set bn "${bn}${locno}"
>      } elseif { $reason == "solib-event" } {
>  	set bn ".*"
>      } elseif { $reason == "exception-caught" } {
>  	set ebn {bkptno="[0-9]+",}
> +	set ebn "${ebn}${locno}"
>  	set bn ".*"
>  	set reason "breakpoint-hit"
>      }
> @@ -1315,6 +1324,7 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set a $after_reason
>  
> 
>      verbose -log "mi_expect_stop: expecting: \\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
> +
>      gdb_expect {
>  	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
>  	    pass "$test"



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-06-06  9:45 [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno Philippe Waroquiers
                   ` (4 preceding siblings ...)
  2022-07-22 16:57 ` Philippe Waroquiers
@ 2022-07-29 18:56 ` Philippe Waroquiers
  2022-08-08  6:52 ` Philippe Waroquiers
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Philippe Waroquiers @ 2022-07-29 18:56 UTC (permalink / raw)
  To: gdb-patches


Ping ^ 5
(Eli reviewed the doc, Keith did a first review)

Thanks
Philippe


On Mon, 2022-06-06 at 11:45 +0200, Philippe Waroquiers wrote:
> Before this patch, when a breakpoint that has multiple locations is reached,
> GDB printed:
>   Thread 1 "zeoes" hit Breakpoint 1, some_func () at somefunc1.c:5
> 
> This patch changes the message so that bkpt_print_id prints the precise
> encountered breakpoint:
>   Thread 1 "zeoes" hit Breakpoint 1.2, some_func () at somefunc1.c:5
> 
> In mi mode, bkpt_print_id also (optionally) prints a new table field "locno":
>   locno is printed when the breakpoint has more than one location.
> Note that according to the GDB user manual node 'GDB/MI Development and Front
> Ends', it is ok to add new fields without changing the MI version.
> 
> Also, when a breakpoint is reached, the convenience variables
> $bkptno and $locno are set to the encountered breakpoint number
> and location number.
> 
> $bkptno and $locno can a.o. be used in the command list of a breakpoint,
> to disable the specific encountered breakpoint, e.g.
>    disable $bkptno.$locno
> 
> In case the breakpoint has only one location, $locno is still set to
> the value 1, so as to allow a command such as:
>   disable $bkptno.$locno
> even when the breakpoint has only one location.
> 
> This also fixes a strange behaviour: when a breakpoint X has only
> one location,
>   enable|disable X.1
> is accepted but transforms the breakpoint in a multiple locations
> breakpoint having only one location.
> 
> The changes in RFA v3 handle the additional comments of Eli:
>  GDB/NEW:
>   - Use max 80-column
>   - Use 'code location' instead of 'location'.
>   - Fix typo $bkpno
>   - Ensure that disable $bkptno and disable $bkptno.$locno have
>     each their explanation inthe example
>   - Reworded the 'breakpoint-hit' paragraph.
>  gdb.texinfo:
>   - Use 'code location' instead of 'location'.
>   - Add a note to clarify the distinction between $bkptno and $bpnum.
>   - Use @kbd instead of examples with only one command.
> 
> Compared to RFA v1, the changes in v2 handle the comments given by
> Keith Seitz and Eli Zaretskii:
>   - Use %s for the result of paddress
>   - Use bkptno_numopt_re instead of 2 different -re cases
>   - use C@t{++}
>   - Add index entries for $bkptno and $locno
>   - Added an example for "locno" in the mi interface
>   - Added examples in the Break command manual.
> ---
>  gdb/NEWS                                      | 21 +++++
>  gdb/ada-lang.c                                |  2 +-
>  gdb/break-catch-syscall.c                     |  2 +-
>  gdb/break-catch-throw.c                       |  2 +-
>  gdb/breakpoint.c                              | 93 +++++++++++++++----
>  gdb/breakpoint.h                              | 14 +++
>  gdb/doc/gdb.texinfo                           | 83 ++++++++++++++++-
>  gdb/infrun.c                                  | 16 +++-
>  gdb/testsuite/gdb.ada/bp_inlined_func.exp     |  2 +-
>  gdb/testsuite/gdb.ada/operator_bp.exp         |  4 +-
>  .../gdb.base/condbreak-multi-context.exp      |  8 +-
>  gdb/testsuite/gdb.base/ctxobj.exp             | 26 ++++--
>  gdb/testsuite/gdb.base/ena-dis-br.exp         | 41 ++++----
>  gdb/testsuite/gdb.base/foll-exec-mode.exp     |  6 +-
>  gdb/testsuite/gdb.base/pie-fork.exp           |  4 +-
>  gdb/testsuite/gdb.base/step-over-exit.exp     |  4 +-
>  gdb/testsuite/gdb.cp/mb-inline.exp            |  4 +-
>  gdb/testsuite/gdb.cp/mb-templates.exp         |  6 +-
>  gdb/testsuite/gdb.cp/ovldbreak.exp            |  6 +-
>  gdb/testsuite/gdb.gdb/python-helper.exp       |  4 +-
>  .../gdb.mi/interrupt-thread-group.exp         |  2 +-
>  .../gdb.mi/user-selected-context-sync.exp     | 35 +++++--
>  gdb/testsuite/gdb.multi/multi-arch-exec.exp   |  3 +-
>  .../gdb.multi/run-only-second-inf.exp         |  2 +-
>  .../gdb.multi/watchpoint-multi-exit.exp       |  4 +-
>  gdb/testsuite/gdb.multi/watchpoint-multi.exp  |  4 +-
>  gdb/testsuite/lib/gdb.exp                     | 11 ++-
>  gdb/testsuite/lib/mi-support.exp              | 20 +++-
>  28 files changed, 335 insertions(+), 94 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 960f90b4387..a5602deee2b 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -34,6 +34,21 @@
>       whitespace from each line before using the string as the help
>       output.
>  
> 
> +* When a breakpoint with multiple code locations is hit, GDB now prints
> +  the code location using the syntax <breakpoint_number>.<location_number>
> +  such as in:
> +     Thread 1 "zeoes" hit Breakpoint 2.3, some_func () at zeoes.c:8
> +
> +* When a breakpoint is hit, GDB now sets the convenience variables $bkptno and
> +  $locno to the hit breakpoint number and code location number.
> +  This allows to disable the last hit breakpoint using
> +     (gdb) disable $bkptno
> +   or disable only the specific breakpoint code location using
> +     (gdb) disable $bkptno.$locno
> +  These commands can be used inside the command list of a breakpoint to
> +  automatically disable the just encountered breakpoint (or the just
> +  encountered specific breakpoint code location).
> +
>  * New commands
>  
> 
>  maintenance set ignore-prologue-end-flag on|off
> @@ -50,6 +65,12 @@ maintenance info line-table
>    entry corresponds to an address where a breakpoint should be placed
>    to be at the first instruction past a function's prologue.
>  
> 
> +* MI changes
> +
> + ** The async record stating the stopped reason 'breakpoint-hit' now
> +    contains an optional field locno giving the code location number
> +    when the breakpoint has multiple code locations.
> +
>  * Python API
>  
> 
>    ** New function gdb.format_address(ADDRESS, PROGSPACE, ARCHITECTURE),
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 6ab01fd27d4..bbae76f39ac 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -12348,7 +12348,7 @@ ada_catchpoint::print_it (const bpstat *bs) const
>  
> 
>    uiout->text (disposition == disp_del
>  	       ? "\nTemporary catchpoint " : "\nCatchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    /* ada_exception_name_addr relies on the selected frame being the
> diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
> index 06d48466de7..82229de33f7 100644
> --- a/gdb/break-catch-syscall.c
> +++ b/gdb/break-catch-syscall.c
> @@ -218,7 +218,7 @@ syscall_catchpoint::print_it (const bpstat *bs) const
>  						: EXEC_ASYNC_SYSCALL_RETURN));
>        uiout->field_string ("disp", bpdisp_text (b->disposition));
>      }
> -  uiout->field_signed ("bkptno", b->number);
> +  print_num_locno (bs, uiout);
>  
> 
>    if (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY)
>      uiout->text (" (call to syscall ");
> diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
> index 66cf80be1c5..5b6f5d9eca1 100644
> --- a/gdb/break-catch-throw.c
> +++ b/gdb/break-catch-throw.c
> @@ -257,7 +257,7 @@ exception_catchpoint::print_it (const bpstat *bs) const
>    bp_temp = disposition == disp_del;
>    uiout->text (bp_temp ? "Temporary catchpoint "
>  		       : "Catchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text ((kind == EX_EVENT_THROW ? " (exception thrown), "
>  		: (kind == EX_EVENT_CATCH ? " (exception caught), "
>  		   : " (exception rethrown), ")));
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index ed932a19ed7..c89c800f32f 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -820,6 +820,19 @@ get_breakpoint (int num)
>    return nullptr;
>  }
>  
> 
> +/* Return TRUE if NUM refer to an existing breakpoint that has
> +   multiple code locations.  */
> +
> +static bool
> +has_multiple_locations (int num)
> +{
> +  for (breakpoint *b : all_breakpoints ())
> +    if (b->number == num)
> +      return b->loc != nullptr && b->loc->next != nullptr;
> +
> +  return false;
> +}
> +
>  \f
>  
> 
>  /* Mark locations as "conditions have changed" in case the target supports
> @@ -4451,15 +4464,7 @@ bpstat_explains_signal (bpstat *bsp, enum gdb_signal sig)
>    return false;
>  }
>  
> 
> -/* Put in *NUM the breakpoint number of the first breakpoint we are
> -   stopped at.  *BSP upon return is a bpstat which points to the
> -   remaining breakpoints stopped at (but which is not guaranteed to be
> -   good for anything but further calls to bpstat_num).
> -
> -   Return 0 if passed a bpstat which does not indicate any breakpoints.
> -   Return -1 if stopped at a breakpoint that has been deleted since
> -   we set it.
> -   Return 1 otherwise.  */
> +/* See breakpoint.h.  */
>  
> 
>  int
>  bpstat_num (bpstat **bsp, int *num)
> @@ -4481,6 +4486,57 @@ bpstat_num (bpstat **bsp, int *num)
>    return 1;
>  }
>  
> 
> +/* See breakpoint.h  */
> +
> +int
> +bpstat_locno (const bpstat *bs)
> +{
> +  const struct breakpoint *b = bs->breakpoint_at;
> +  const struct bp_location *bl = bs->bp_location_at.get ();
> +
> +  int locno = 0;
> +
> +  if (b != nullptr && b->loc->next != nullptr)
> +    {
> +      const bp_location *bl_i;
> +
> +      for (bl_i = b->loc;
> +	   bl_i != bl && bl_i->next != nullptr;
> +	   bl_i = bl_i->next)
> +	locno++;
> +
> +      if (bl_i == bl)
> +	locno++;
> +      else
> +	{
> +	  warning (_("location number not found for breakpoint %d address %s."),
> +		   b->number, paddress (bl->gdbarch, bl->address));
> +	  locno = 0;
> +	}
> +    }
> +
> +  return locno;
> +}
> +
> +/* See breakpoint.h.  */
> +
> +void
> +print_num_locno (const bpstat *bs, struct ui_out *uiout)
> +{
> +  struct breakpoint *b = bs->breakpoint_at;
> +
> +  if (b == nullptr)
> +    uiout->text (_("deleted breakpoint"));
> +  else
> +    {
> +      uiout->field_signed ("bkptno", b->number);
> +
> +      int locno = bpstat_locno (bs);
> +      if (locno != 0)
> +	uiout->message (".%pF", signed_field ("locno", locno));
> +    }
> +}
> +
>  /* See breakpoint.h.  */
>  
> 
>  void
> @@ -9176,7 +9232,7 @@ ranged_breakpoint::print_it (const bpstat *bs) const
>  		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
> @@ -11610,12 +11666,13 @@ ordinary_breakpoint::print_it (const bpstat *bs) const
>  			   async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> +
>    if (bp_temp)
> -    uiout->message ("Temporary breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Temporary breakpoint ");
>    else
> -    uiout->message ("Breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Breakpoint ");
> +  print_num_locno (bs, uiout);
> +  uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
>  }
> @@ -13220,9 +13277,13 @@ enable_disable_command (const char *args, int from_tty, bool enable)
>  	  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)
> +	      && (bp_loc_range.first == 0
> +		  || (bp_loc_range.first == 1
> +		      && bp_num_range.first == bp_num_range.second
> +		      && !has_multiple_locations (bp_num_range.first))))
>  	    {
> -	      /* Handle breakpoint ids with formats 'x' or 'x-z'.  */
> +	      /* Handle breakpoint ids with formats 'x' or 'x-z'
> +		 or 'y.1' where y has only one code location.  */
>  	      map_breakpoint_number_range (bp_num_range,
>  					   enable
>  					   ? enable_breakpoint
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 566f1285e46..96d61ef5427 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -1231,6 +1231,20 @@ extern enum print_stop_action bpstat_print (bpstat *, int);
>     Return 1 otherwise.  */
>  extern int bpstat_num (bpstat **, int *);
>  
> 
> +/* If BS indicates a breakpoint and this breakpoint has several code locations,
> +   return the location number of BS, otherwise return 0.  */
> +
> +extern int bpstat_locno (const bpstat *bs);
> +
> +/* Print BS breakpoint number optionally followed by a . and breakpoint locno.
> +
> +   For a breakpoint with only one code location, outputs the signed field
> +   "bkptno" breakpoint number of BS (as returned by bpstat_num).
> +   If BS has several code locations, outputs a '.' character followed by
> +   the signed field "locno" (as returned by bpstat_locno).  */
> +
> +extern void print_num_locno (const bpstat *bs, struct ui_out *);
> +
>  /* Perform actions associated with the stopped inferior.  Actually, we
>     just use this for breakpoint commands.  Perhaps other actions will
>     go here later, but this is executed at a late time (from the
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 434add3a663..391b81f8863 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -4338,9 +4338,65 @@ are operated on.
>  @cindex latest breakpoint
>  Breakpoints are set with the @code{break} command (abbreviated
>  @code{b}).  The debugger convenience variable @samp{$bpnum} records the
> -number of the breakpoint you've set most recently; see @ref{Convenience
> -Vars,, Convenience Variables}, for a discussion of what you can do with
> -convenience variables.
> +number of the breakpoint you've set most recently:
> +@smallexample
> +(gdb) b main
> +Breakpoint 1 at 0x11c6: file zeoes.c, line 24.
> +(gdb) p $bpnum
> +$1 = 1
> +@end smallexample
> +
> +A breakpoint may be mapped to multiple code locations for example with
> +inlined functions, Ada generics, C@t{++} templates or overloaded function names.
> +@value{GDBN} then indicates the number of code locations in the breakpoint
> +command output:
> +@smallexample
> +(gdb) b some_func
> +Breakpoint 2 at 0x1179: some_func. (3 locations)
> +(gdb) p $bpnum
> +$2 = 2
> +(gdb)
> +@end smallexample
> +
> +@vindex $bkptno@r{, convenience variable}
> +@vindex $locno@r{, convenience variable}
> +When your program stops on a breakpoint, the convenience variables
> +@samp{$bkptno} and @samp{$locno} are respectively set to the number of
> +the encountered breakpoint and the number of the breakpoint's code location:
> +@smallexample
> +Thread 1 "zeoes" hit Breakpoint 2.1, some_func () at zeoes.c:8
> +8	  printf("some func\n");
> +(gdb) p $bkptno
> +$5 = 2
> +(gdb) p $locno
> +$6 = 1
> +(gdb)
> +@end smallexample
> +
> +Note that @samp{$bkptno} and @samp{$bpnum} are not equivalent:
> +@samp{$bkptno} is set to the breakpoint number @b{last hit}, while
> +@samp{$bpnum} is set to the breakpoint number @b{last set}.
> +
> +
> +If the encountered breakpoint has only one code location, @samp{$locno} is set
> +to 1:
> +@smallexample
> +Breakpoint 1, main (argc=1, argv=0x7fffffffe018) at zeoes.c:24
> +24	  if (argc > 1)
> +(gdb) p $bkptno
> +$3 = 1
> +(gdb) p $locno
> +$4 = 1
> +(gdb)
> +@end smallexample
> +
> +The @samp{$bkptno} and @samp{$locno} variables can typically be used
> +in a breakpoint command list.
> +(@pxref{Break Commands, ,Breakpoint Command Lists}). For example, as
> +part of the breakpoint command list, you can disable completely the
> +encountered breakpoint using @samp{disable $bkptno} or disable the
> +specific encountered breakpoint location using @samp{disable
> +$bkptno.$locno}.
>  
> 
>  @table @code
>  @item break @var{locspec}
> @@ -5739,6 +5795,13 @@ Expressions}).
>  Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
>  disabled within a @var{command-list}.
>  
> 
> +Inside a command list, you can use the command
> +@kbd{disable $bkptno} to disable the encountered breakpoint.
> +
> +If your breakpoint has several code locations, the command
> +@kbd{disable $bkptno.$locno} will disable the specific breakpoint code
> +location encountered.
> +
>  You can use breakpoint commands to start your program up again.  Simply
>  use the @code{continue} command, or @code{step}, or any other command
>  that resumes execution.
> @@ -32570,6 +32633,20 @@ line="13",arch="i386:x86_64"@}
>  (gdb)
>  @end smallexample
>  
> 
> +For a @samp{breakpoint-hit} stopped reason, when the breakpoint
> +encountered has multiple locations, the field @samp{bkptno} is
> +followed by the field @samp{locno}.
> +
> +@smallexample
> +-exec-continue
> +^running
> +(gdb)
> +@@Hello world
> +*stopped,reason="breakpoint-hit",disp="keep",bkptno="2",locno="3",frame=@{
> +func="foo",args=[],file="hello.c",fullname="/home/foo/bar/hello.c",
> +line="13",arch="i386:x86_64"@}
> +(gdb)
> +@end smallexample
>  
> 
>  @subheading The @code{-exec-finish} Command
>  @findex -exec-finish
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 02c98b50c8c..e5ad062a914 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -8494,7 +8494,21 @@ print_stop_location (const target_waitstatus &ws)
>       LOCATION: Print only location
>       SRC_AND_LOC: Print location and source line.  */
>    if (do_frame_printing)
> -    print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    {
> +      if (tp->control.stop_bpstat != nullptr)
> +	{
> +	  const struct breakpoint *b = tp->control.stop_bpstat->breakpoint_at;
> +
> +	  if (b != nullptr)
> +	    {
> +	      int locno = bpstat_locno (tp->control.stop_bpstat);
> +	      set_internalvar_integer (lookup_internalvar ("bkptno"), b->number);
> +	      set_internalvar_integer (lookup_internalvar ("locno"),
> +				       (locno > 0 ? locno : 1));
> +	    }
> +	}
> +      print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    }
>  }
>  
> 
>  /* See infrun.h.  */
> diff --git a/gdb/testsuite/gdb.ada/bp_inlined_func.exp b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> index 076e8c2425f..3f94c163819 100644
> --- a/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> +++ b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> @@ -42,7 +42,7 @@ gdb_test "break read_small" \
>  for {set i 0} {$i < 4} {incr i} {
>      with_test_prefix "iteration $i" {
>  	gdb_test "continue" \
> -	    "Breakpoint $decimal, b\\.read_small \\(\\).*" \
> +	    "Breakpoint $bkptno_num_re, b\\.read_small \\(\\).*" \
>  	    "stopped in read_small"
>      }
>  }
> diff --git a/gdb/testsuite/gdb.ada/operator_bp.exp b/gdb/testsuite/gdb.ada/operator_bp.exp
> index 655e7af479f..e3928419ed6 100644
> --- a/gdb/testsuite/gdb.ada/operator_bp.exp
> +++ b/gdb/testsuite/gdb.ada/operator_bp.exp
> @@ -56,7 +56,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to \"$op\""
>  }
>  
> 
> @@ -86,7 +86,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to ops.\"$op\""
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> index b540df973a3..742315178e3 100644
> --- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> +++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> @@ -140,11 +140,11 @@ with_test_prefix "scenario 1" {
>      gdb_run_cmd
>  
> 
>      # Check our conditional breakpoints.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> @@ -208,11 +208,11 @@ with_test_prefix "scenario 2" {
>      gdb_run_cmd
>  
> 
>      # Check that we hit enabled locations only.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> diff --git a/gdb/testsuite/gdb.base/ctxobj.exp b/gdb/testsuite/gdb.base/ctxobj.exp
> index 9c010f54d79..0b589a7d6e6 100644
> --- a/gdb/testsuite/gdb.base/ctxobj.exp
> +++ b/gdb/testsuite/gdb.base/ctxobj.exp
> @@ -67,9 +67,16 @@ gdb_test "break ctxobj-f.c:$bp_location" \
>           "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
>           "break in get_version functions"
>  
> 
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_1 \\(\\).*" \
> -         "continue to get_version_1"
> +global expect_out
> +set test "continue to get_version_1"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_1 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  # Try printing "this_version_num".  There are two global variables
>  # with that name, and some systems such as GNU/Linux merge them
> @@ -100,10 +107,15 @@ gdb_test "print this_version_num == v" \
>          "print libctxobj1's this_version_num from symtab"
>  
> 
>  # Do the same, but from get_version_2.
> -
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_2 \\(\\).*" \
> -         "continue to get_version_2"
> +set test "continue to get_version_2"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_2 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  gdb_test "print this_version_num == v" \
>           " = 1" \
> diff --git a/gdb/testsuite/gdb.base/ena-dis-br.exp b/gdb/testsuite/gdb.base/ena-dis-br.exp
> index 24925cf7185..04b3f134b44 100644
> --- a/gdb/testsuite/gdb.base/ena-dis-br.exp
> +++ b/gdb/testsuite/gdb.base/ena-dis-br.exp
> @@ -67,14 +67,21 @@ gdb_test "info break $bp" \
>  # See the comments in condbreak.exp for "run until breakpoint at
>  # marker1" for an explanation of the xfail below.
>  set test "continue to break marker1"
> +set bpno 0
>  gdb_test_multiple "continue" "$test" {
> -    -re "Breakpoint \[0-9\]*, marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	pass "$test"
>      }
> -    -re "Breakpoint \[0-9\]*, $hex in marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), $hex in marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	xfail "$test"
>      }
>  }
> +# Verify the $bkptno convenience variable is equal to the hit bpno.
> +gdb_test "print \$bkptno" " = $bpno" "$test \$bkptno is $bpno"
> +# Verify the $locno is 1, as there is only one code location.
> +gdb_test "print \$locno" " = 1" "$test \$locno is 1"
>  
> 
>  gdb_test_no_output "delete $bp" "delete break marker1"
>  
> 
> @@ -359,7 +366,8 @@ with_test_prefix "4th breakpoint" {
>  }
>  
> 
>  # Perform tests for disable/enable commands on multiple
> -# locations and breakpoints.
> +# code locations and breakpoints.  If a breakpoint has only one code location,
> +# enable/disable num  and enable/disable num.1 should be equivalent.
>  #
>  # WHAT - the command to test (disable/enable).
>  #
> @@ -372,7 +380,7 @@ proc test_ena_dis_br { what } {
>      global b3
>      global b4
>      global gdb_prompt
> -    
> +
>      # OPPOS    - the command opposite to WHAT.
>      # WHAT_RES - whether breakpoints are expected to end
>      #            up enabled or disabled.
> @@ -395,13 +403,13 @@ proc test_ena_dis_br { what } {
>  	set p2 "pass"
>      }
>  
> 
> -    # Now enable(disable) $b.1 $b2.1.
> +    # Now enable(disable) $b1.1 $b2.1.
>      gdb_test_no_output "$what $b1.1 $b2.1" "$what \$b1.1 \$b2.1"
>      set test1 "${what}d \$b1.1 and \$b2.1"
>  
> 
>      # Now $b1.1 and $b2.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -       -re "(${b1}.1)(\[^\n\r\]*)( n.*)(${b2}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +       -re "(${b1})(\[^\n\r\]*)( n.*)(${b2})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> @@ -420,19 +428,16 @@ proc test_ena_dis_br { what } {
>         "${what}d \$b1"
>  
> 
>      gdb_test_no_output "$oppos $b3" "$oppos \$b3"
> +    # Now $b4 $b3 should be enabled(disabled)
> +    set test1 "${what}d \$b4 and \$b3"
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $oppos_res.*).*(${b4})(\[^\n\r\]*)( $oppos_res.*)" "$test1"
> +
>      gdb_test_no_output "$what $b4 $b3.1" "$what \$b4 \$b3.1"
> -    set test1 "${what}d \$b4 and \$b3.1,remain ${oppos}d \$b3"
> +    set test1 "${what}d \$b4 and \$b3.1, changing \$b3"
> +
> +    # Now $b4 $b3 should be enabled(disabled)
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $what_res.*).*(${b4})(\[^\n\r\]*)( $what_res.*)" "$test1"
>  
> 
> -    # Now $b4 $b3.1 should be enabled(disabled) and
> -    # $b3 should remain disabled(enabled).
> -    gdb_test_multiple "info break" "$test1" {
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b3}.1)(\[^\n\r\]*)( n.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p1 "$test1"
> -       }
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p2 "$test1"
> -       }
> -    }
>  
> 
>      # Now enable(disable) '$b4.1 fooobaar'.  This should error on
>      # fooobaar.
> @@ -443,7 +448,7 @@ proc test_ena_dis_br { what } {
>  
> 
>      # $b4.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -        -re "(${b4}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +        -re "(${b4})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.base/foll-exec-mode.exp b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> index 918f3e4fd5f..cb6d975a767 100644
> --- a/gdb/testsuite/gdb.base/foll-exec-mode.exp
> +++ b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> @@ -99,7 +99,7 @@ proc do_catch_exec_test { } {
>  # before re-running.
>  
> 
>  proc do_follow_exec_mode_tests { mode cmd infswitch } {
> -    global binfile srcfile srcfile2 testfile testfile2
> +    global binfile srcfile srcfile2 testfile testfile2 bkptno_numopt_re
>      global gdb_prompt
>  
> 
>      with_test_prefix "$mode,$cmd,$infswitch" {
> @@ -125,7 +125,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  	# Set up the output we expect to see after we execute past the exec.
>  	#
>  	set execd_line [gdb_get_line_number "after-exec" $srcfile2]
> -	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint .,.*${srcfile2}:${execd_line}.*$gdb_prompt $"
> +	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint ${bkptno_numopt_re},.*${srcfile2}:${execd_line}.*$gdb_prompt $"
>  
> 
>  	# Set a breakpoint after the exec call if we aren't single-stepping
>  	# past it.
> @@ -189,7 +189,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  		send_gdb "y\n"
>  		exp_continue
>  	    }
> -	    -re "Starting program: .*$expected_inf.*Breakpoint .,.*\r\n$gdb_prompt $" {
> +	    -re "Starting program: .*$expected_inf.*Breakpoint $bkptno_numopt_re,.*\r\n$gdb_prompt $" {
>  		pass $test
>  	    }
>  	}
> diff --git a/gdb/testsuite/gdb.base/pie-fork.exp b/gdb/testsuite/gdb.base/pie-fork.exp
> index efc357d39a2..19e9d3a5537 100644
> --- a/gdb/testsuite/gdb.base/pie-fork.exp
> +++ b/gdb/testsuite/gdb.base/pie-fork.exp
> @@ -54,10 +54,10 @@ proc_with_prefix test_detach_on_fork_follow_child {} {
>  proc_with_prefix test_no_detach_on_fork {} {
>      setup_test "off"
>  
> 
> -    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2.1, break_here.*" \
>  	     "continue from thread 1.1"
>      gdb_test "thread 2.1"
> -    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2.2, break_here.*" \
>  	     "continue from thread 2.1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/step-over-exit.exp b/gdb/testsuite/gdb.base/step-over-exit.exp
> index f8bd99980fe..575319c564c 100644
> --- a/gdb/testsuite/gdb.base/step-over-exit.exp
> +++ b/gdb/testsuite/gdb.base/step-over-exit.exp
> @@ -91,7 +91,7 @@ delete_breakpoints
>  
> 
>  gdb_test "break marker"
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_num_re, .*" \
>      "continue to marker, first time"
>  
> 
>  # Step 2, create a breakpoint which evaluates false, and force it
> @@ -120,5 +120,5 @@ gdb_test "inferior 1" ".*Switching to inferior 1.*" \
>  # Switch back to the parent process, continue to the marker to
>  # test GDBserver's state is still correct.
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_numopt_re, .*" \
>      "continue to marker, second time"
> diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
> index 47a2a5dcb7c..fa098602c31 100644
> --- a/gdb/testsuite/gdb.cp/mb-inline.exp
> +++ b/gdb/testsuite/gdb.cp/mb-inline.exp
> @@ -46,7 +46,7 @@ gdb_test "info break" \
>      "\[\r\n\]1\.1.* y .* at .*$hdrfile:$bp_location.*\[\r\n\]1\.2.* y .* at .*$hdrfile:$bp_location.*"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo \\(i=1\\).*" \
> @@ -59,7 +59,7 @@ gdb_test "continue" \
>  gdb_test_no_output "disable 1.2" "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
>  
> 
>  gdb_test_multiple "info break" "disabled breakpoint 1.2" {
>      -re "1\.2.* n .* at .*$hdrfile:$bp_location.*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
> index 6c988e7335e..0c0d46fcb7a 100644
> --- a/gdb/testsuite/gdb.cp/mb-templates.exp
> +++ b/gdb/testsuite/gdb.cp/mb-templates.exp
> @@ -42,7 +42,7 @@ gdb_run_cmd
>  
> 
>  set test "initial condition: run to breakpoint"
>  gdb_test_multiple "" $test {
> -    -re "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
> +    -re "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
>  	pass $test
>  	break
>      }
> @@ -67,7 +67,7 @@ gdb_test_no_output {condition $bpnum i==1} \
>      "separate condition: set condition"
>      
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo<double> \\(i=1\\).*" \
> @@ -79,7 +79,7 @@ gdb_test "continue" \
>  gdb_test_no_output {disable $bpnum.1} "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
>  
> 
>  # Try disabling entire breakpoint
>  gdb_test_no_output {enable $bpnum.1} "disabling location: enable"
> diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
> index 06adf82ecbb..0ed9eae055b 100644
> --- a/gdb/testsuite/gdb.cp/ovldbreak.exp
> +++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
> @@ -380,7 +380,7 @@ gdb_test "info break" $bptable "breakpoint info (after setting on all)"
>  
> 
>  # Run through each breakpoint.
>  proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
> -    global gdb_prompt hex decimal srcfile
> +    global gdb_prompt hex decimal srcfile bkptno_num_re
>  
> 
>      if {$argument == ""} {
>          set actuals ""
> @@ -398,11 +398,11 @@ proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
>      }
>  
> 
>      gdb_test_multiple "continue" "continue to bp overloaded : $argtype" {
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              pass "continue to bp overloaded : $argtype"
>          }
>  
> 
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              if $might_kfail {
>                  kfail "c++/8130" "continue to bp overloaded : $argtype"
>              } else {
> diff --git a/gdb/testsuite/gdb.gdb/python-helper.exp b/gdb/testsuite/gdb.gdb/python-helper.exp
> index 6db8bf0df50..30eb6038f3a 100644
> --- a/gdb/testsuite/gdb.gdb/python-helper.exp
> +++ b/gdb/testsuite/gdb.gdb/python-helper.exp
> @@ -49,7 +49,7 @@ gdb_exit
>  # The main test.  This is called by the self-test framework once GDB
>  # has been started on a copy of itself.
>  proc test_python_helper {} {
> -    global py_helper_script decimal hex gdb_prompt
> +    global py_helper_script decimal hex gdb_prompt bkptno_numopt_re
>      global inferior_spawn_id
>  
> 
>      # Source the python helper script.  This script registers the
> @@ -233,7 +233,7 @@ proc test_python_helper {} {
>      # GDB stopping at the value_print breakpoint again.
>      send_inferior "ptype global_c\n"
>      gdb_test_multiple "" "hit breakpoint in outer gdb again" {
> -	-re "Breakpoint $decimal, c_print_type .*\\(outer-gdb\\) $" {
> +	-re "Breakpoint $bkptno_numopt_re, c_print_type .*\\(outer-gdb\\) $" {
>  	    pass $gdb_test_name
>  	}
>      }
> diff --git a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> index 19ccbe85e04..c080955049c 100644
> --- a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> +++ b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> @@ -69,7 +69,7 @@ if { $use_second_inferior } {
>  	"\\^running.*" \
>  	"run inferior 2"
>  
> 
> -    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\""} \
> +    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\"" "locno=\"[0-9]+\""} \
>  	"inferior i2 stops at all_threads_started"
>  
> 
>      mi_send_resuming_command "exec-continue --thread-group i2" \
> diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> index d78c96ddef1..9eec083068b 100644
> --- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> +++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> @@ -307,8 +307,13 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  	    # Consume MI event output.
>  	    with_spawn_id $mi_spawn_id {
> -		mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> -		    "$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		if { $inf == 1 } {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		} else {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} "stop at breakpoint in main"
> +		}
>  	    }
>  
> 
>  	    if { $mode == "all-stop" } {
> @@ -330,9 +335,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		    # Consume MI output.
>  		    with_spawn_id $mi_spawn_id {
> -			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			    "thread $inf.$thread stops MI"
> +			if { $inf == 1} {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +				"thread $inf.$thread stops MI"
> +			} else {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +				"thread $inf.$thread stops MI"
> +			}
>  		    }
>  		}
>  
> 
> @@ -359,9 +370,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		# Consume MI output.
>  		with_spawn_id $mi_spawn_id {
> -		    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			"thread $inf.2 stops MI"
> +		    if { $inf == 1} {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +			    "thread $inf.2 stops MI"
> +		    } else {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +			    "thread $inf.2 stops MI"
> +		    }
>  		}
>  	    }
>  	}
> @@ -434,7 +451,7 @@ proc_with_prefix test_setup { mode } {
>  
> 
>  	with_spawn_id $mi_spawn_id {
>  	    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" "$decimal" \
> -		{"" "disp=\"del\""} "main stop"
> +		{"" "disp=\"del\"" "locno=\"[0-9]+\""} "main stop"
>  	}
>  
> 
>  	# Consume CLI output.
> diff --git a/gdb/testsuite/gdb.multi/multi-arch-exec.exp b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> index a1496fb5571..dfdb746c65e 100644
> --- a/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> +++ b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> @@ -148,6 +148,7 @@ proc build_executables { first_arch } {
>  }
>  
> 
>  proc do_test { first_arch mode selected_thread } {
> +        global bkptno_numopt_re
>  	set from_exec "$first_arch-multi-arch-exec"
>  
> 
>  	clean_restart ${from_exec}
> @@ -169,7 +170,7 @@ proc do_test { first_arch mode selected_thread } {
>  
> 
>  	# Test that GDB updates the target description / arch successfuly
>  	# after the exec.
> -	gdb_test "continue" "Breakpoint 2, main.*" "continue across exec that changes architecture"
> +	gdb_test "continue" "Breakpoint $bkptno_numopt_re, main.*" "continue across exec that changes architecture"
>  }
>  
> 
>  # Test both arch1=>arch2 and arch2=>arch1.
> diff --git a/gdb/testsuite/gdb.multi/run-only-second-inf.exp b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> index fec2575f904..b94689d0bfa 100644
> --- a/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> +++ b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> @@ -46,5 +46,5 @@ gdb_load $binfile
>  if {[gdb_start_cmd] < 0} {
>      fail "start the second inf"
>  } else {
> -    gdb_test "" ".*reakpoint ., main .*${srcfile}.*" "start the second inf"
> +    gdb_test "" ".*reakpoint $bkptno_numopt_re, main .*${srcfile}.*" "start the second inf"
>  }
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> index cbccba19d12..3c079facced 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> @@ -27,7 +27,7 @@ if {[build_executable "failed to build" $testfile $srcfile {debug}]} {
>  # child.  Can be either "kill", "detach", or "exit" (to continue it to
>  # normal exit).
>  proc do_test {dispose} {
> -    global binfile
> +    global binfile bkptno_numopt_re
>  
> 
>      clean_restart $binfile
>  
> 
> @@ -77,7 +77,7 @@ proc do_test {dispose} {
>      #  Command aborted.
>      #  (gdb)
>      #
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker .*" \
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker .*" \
>  	"continue in inferior 1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi.exp b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> index e4329dca6c2..0fc1bee762f 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> @@ -84,11 +84,11 @@ if [skip_hw_watchpoint_multi_tests] {
>  	"Hardware access \\(read/write\\) watchpoint \[0-9\]+: c\r\n\r\nOld value = 0\r\nNew value = 3\r\n.*" \
>  	"catch c on inferior 2"
>  
> 
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 2"
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 2"
>  
> 
>      gdb_test "inferior 1" "witching to inferior 1 .*" "switch back to inferior 1 again"
>  
> 
>      gdb_test "continue" "Hardware access \\(read/write\\) watchpoint \[0-9\]+: b\r\n\r\nOld value = 0\r\nNew value = 2\r\n.*" "catch b on inferior 1"
>  }
>  
> 
> -gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 1"
> +gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 1"
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 402450152ac..5e4c793598e 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -227,6 +227,14 @@ set inferior_exited_re "(?:\\\[Inferior \[0-9\]+ \\(\[^\n\r\]*\\) exited)"
>  # E.g., $1, $2, etc.
>  set valnum_re "\\\$$decimal"
>  
> 
> +# A regular expression that matches a breakpoint hit with a breakpoint
> +# having several code locations.
> +set bkptno_num_re "$decimal\\.$decimal"
> +
> +# A regular expression that matches a breakpoint hit
> +# with one or several code locations.
> +set bkptno_numopt_re "($decimal\\.$decimal|$decimal)"
> +
>  ### Only procedures should come after this point.
>  
> 
>  #
> @@ -662,6 +670,7 @@ proc gdb_breakpoint { linespec args } {
>  
> 
>  proc runto { linespec args } {
>      global gdb_prompt
> +    global bkptno_numopt_re
>      global decimal
>  
> 
>      delete_breakpoints
> @@ -699,7 +708,7 @@ proc runto { linespec args } {
>  	    }
>  	    return 1
>  	}
> -	-re "Breakpoint \[0-9\]*, \[0-9xa-f\]* in .*$gdb_prompt $" { 
> +	-re "Breakpoint $bkptno_numopt_re, \[0-9xa-f\]* in .*$gdb_prompt $" {
>  	    if { $print_pass } {
>  		pass $test_name
>  	    }
> diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
> index e578a7e6f9b..ea66fdcabf8 100644
> --- a/gdb/testsuite/lib/mi-support.exp
> +++ b/gdb/testsuite/lib/mi-support.exp
> @@ -1195,11 +1195,11 @@ proc mi_detect_async {} {
>  # filename of a file without debug info.  ARGS should not include [] the
>  # list of argument is enclosed in, and other regular expressions should
>  # not include quotes.
> -# If EXTRA is a list of one element, it's the regular expression
> +# EXTRA can be a list of one, two or three elements.
> +# The first element is the regular expression
>  # for output expected right after *stopped, and before GDB prompt.
> -# If EXTRA is a list of two elements, the first element is for
> -# output right after *stopped, and the second element is output
> -# right after reason field.  The regex after reason should not include
> +# The third element is the regulation expression for the locno
> +# right after bkptno field.  The locno regex should not include
>  # the comma separating it from the following fields.
>  #
>  # When we fail to match output at all, -1 is returned.  If FILE does
> @@ -1224,7 +1224,14 @@ proc mi_expect_stop { reason func args file line extra test } {
>  
> 
>      set after_stopped ""
>      set after_reason ""
> -    if { [llength $extra] == 2 } {
> +    set locno ""
> +    if { [llength $extra] == 3 } {
> +	set after_stopped [lindex $extra 0]
> +	set after_reason [lindex $extra 1]
> +	set after_reason "${after_reason},"
> +	set locno [lindex $extra 2]
> +	set locno "${locno},"
> +    } elseif { [llength $extra] == 2 } {
>  	set after_stopped [lindex $extra 0]
>  	set after_reason [lindex $extra 1]
>  	set after_reason "${after_reason},"
> @@ -1298,10 +1305,12 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set ebn ""
>      if { $reason == "breakpoint-hit" } {
>  	set bn {bkptno="[0-9]+",}
> +	set bn "${bn}${locno}"
>      } elseif { $reason == "solib-event" } {
>  	set bn ".*"
>      } elseif { $reason == "exception-caught" } {
>  	set ebn {bkptno="[0-9]+",}
> +	set ebn "${ebn}${locno}"
>  	set bn ".*"
>  	set reason "breakpoint-hit"
>      }
> @@ -1315,6 +1324,7 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set a $after_reason
>  
> 
>      verbose -log "mi_expect_stop: expecting: \\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
> +
>      gdb_expect {
>  	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
>  	    pass "$test"



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-06-06  9:45 [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno Philippe Waroquiers
                   ` (5 preceding siblings ...)
  2022-07-29 18:56 ` Philippe Waroquiers
@ 2022-08-08  6:52 ` Philippe Waroquiers
  2022-08-14 14:08 ` Philippe Waroquiers
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Philippe Waroquiers @ 2022-08-08  6:52 UTC (permalink / raw)
  To: gdb-patches

Ping ^ 6
(Eli reviewed the doc, Keith did a first review)

Thanks
Philippe


On Mon, 2022-06-06 at 11:45 +0200, Philippe Waroquiers wrote:
> Before this patch, when a breakpoint that has multiple locations is reached,
> GDB printed:
>   Thread 1 "zeoes" hit Breakpoint 1, some_func () at somefunc1.c:5
> 
> This patch changes the message so that bkpt_print_id prints the precise
> encountered breakpoint:
>   Thread 1 "zeoes" hit Breakpoint 1.2, some_func () at somefunc1.c:5
> 
> In mi mode, bkpt_print_id also (optionally) prints a new table field "locno":
>   locno is printed when the breakpoint has more than one location.
> Note that according to the GDB user manual node 'GDB/MI Development and Front
> Ends', it is ok to add new fields without changing the MI version.
> 
> Also, when a breakpoint is reached, the convenience variables
> $bkptno and $locno are set to the encountered breakpoint number
> and location number.
> 
> $bkptno and $locno can a.o. be used in the command list of a breakpoint,
> to disable the specific encountered breakpoint, e.g.
>    disable $bkptno.$locno
> 
> In case the breakpoint has only one location, $locno is still set to
> the value 1, so as to allow a command such as:
>   disable $bkptno.$locno
> even when the breakpoint has only one location.
> 
> This also fixes a strange behaviour: when a breakpoint X has only
> one location,
>   enable|disable X.1
> is accepted but transforms the breakpoint in a multiple locations
> breakpoint having only one location.
> 
> The changes in RFA v3 handle the additional comments of Eli:
>  GDB/NEW:
>   - Use max 80-column
>   - Use 'code location' instead of 'location'.
>   - Fix typo $bkpno
>   - Ensure that disable $bkptno and disable $bkptno.$locno have
>     each their explanation inthe example
>   - Reworded the 'breakpoint-hit' paragraph.
>  gdb.texinfo:
>   - Use 'code location' instead of 'location'.
>   - Add a note to clarify the distinction between $bkptno and $bpnum.
>   - Use @kbd instead of examples with only one command.
> 
> Compared to RFA v1, the changes in v2 handle the comments given by
> Keith Seitz and Eli Zaretskii:
>   - Use %s for the result of paddress
>   - Use bkptno_numopt_re instead of 2 different -re cases
>   - use C@t{++}
>   - Add index entries for $bkptno and $locno
>   - Added an example for "locno" in the mi interface
>   - Added examples in the Break command manual.
> ---
>  gdb/NEWS                                      | 21 +++++
>  gdb/ada-lang.c                                |  2 +-
>  gdb/break-catch-syscall.c                     |  2 +-
>  gdb/break-catch-throw.c                       |  2 +-
>  gdb/breakpoint.c                              | 93 +++++++++++++++----
>  gdb/breakpoint.h                              | 14 +++
>  gdb/doc/gdb.texinfo                           | 83 ++++++++++++++++-
>  gdb/infrun.c                                  | 16 +++-
>  gdb/testsuite/gdb.ada/bp_inlined_func.exp     |  2 +-
>  gdb/testsuite/gdb.ada/operator_bp.exp         |  4 +-
>  .../gdb.base/condbreak-multi-context.exp      |  8 +-
>  gdb/testsuite/gdb.base/ctxobj.exp             | 26 ++++--
>  gdb/testsuite/gdb.base/ena-dis-br.exp         | 41 ++++----
>  gdb/testsuite/gdb.base/foll-exec-mode.exp     |  6 +-
>  gdb/testsuite/gdb.base/pie-fork.exp           |  4 +-
>  gdb/testsuite/gdb.base/step-over-exit.exp     |  4 +-
>  gdb/testsuite/gdb.cp/mb-inline.exp            |  4 +-
>  gdb/testsuite/gdb.cp/mb-templates.exp         |  6 +-
>  gdb/testsuite/gdb.cp/ovldbreak.exp            |  6 +-
>  gdb/testsuite/gdb.gdb/python-helper.exp       |  4 +-
>  .../gdb.mi/interrupt-thread-group.exp         |  2 +-
>  .../gdb.mi/user-selected-context-sync.exp     | 35 +++++--
>  gdb/testsuite/gdb.multi/multi-arch-exec.exp   |  3 +-
>  .../gdb.multi/run-only-second-inf.exp         |  2 +-
>  .../gdb.multi/watchpoint-multi-exit.exp       |  4 +-
>  gdb/testsuite/gdb.multi/watchpoint-multi.exp  |  4 +-
>  gdb/testsuite/lib/gdb.exp                     | 11 ++-
>  gdb/testsuite/lib/mi-support.exp              | 20 +++-
>  28 files changed, 335 insertions(+), 94 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 960f90b4387..a5602deee2b 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -34,6 +34,21 @@
>       whitespace from each line before using the string as the help
>       output.
>  
> 
> +* When a breakpoint with multiple code locations is hit, GDB now prints
> +  the code location using the syntax <breakpoint_number>.<location_number>
> +  such as in:
> +     Thread 1 "zeoes" hit Breakpoint 2.3, some_func () at zeoes.c:8
> +
> +* When a breakpoint is hit, GDB now sets the convenience variables $bkptno and
> +  $locno to the hit breakpoint number and code location number.
> +  This allows to disable the last hit breakpoint using
> +     (gdb) disable $bkptno
> +   or disable only the specific breakpoint code location using
> +     (gdb) disable $bkptno.$locno
> +  These commands can be used inside the command list of a breakpoint to
> +  automatically disable the just encountered breakpoint (or the just
> +  encountered specific breakpoint code location).
> +
>  * New commands
>  
> 
>  maintenance set ignore-prologue-end-flag on|off
> @@ -50,6 +65,12 @@ maintenance info line-table
>    entry corresponds to an address where a breakpoint should be placed
>    to be at the first instruction past a function's prologue.
>  
> 
> +* MI changes
> +
> + ** The async record stating the stopped reason 'breakpoint-hit' now
> +    contains an optional field locno giving the code location number
> +    when the breakpoint has multiple code locations.
> +
>  * Python API
>  
> 
>    ** New function gdb.format_address(ADDRESS, PROGSPACE, ARCHITECTURE),
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 6ab01fd27d4..bbae76f39ac 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -12348,7 +12348,7 @@ ada_catchpoint::print_it (const bpstat *bs) const
>  
> 
>    uiout->text (disposition == disp_del
>  	       ? "\nTemporary catchpoint " : "\nCatchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    /* ada_exception_name_addr relies on the selected frame being the
> diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
> index 06d48466de7..82229de33f7 100644
> --- a/gdb/break-catch-syscall.c
> +++ b/gdb/break-catch-syscall.c
> @@ -218,7 +218,7 @@ syscall_catchpoint::print_it (const bpstat *bs) const
>  						: EXEC_ASYNC_SYSCALL_RETURN));
>        uiout->field_string ("disp", bpdisp_text (b->disposition));
>      }
> -  uiout->field_signed ("bkptno", b->number);
> +  print_num_locno (bs, uiout);
>  
> 
>    if (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY)
>      uiout->text (" (call to syscall ");
> diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
> index 66cf80be1c5..5b6f5d9eca1 100644
> --- a/gdb/break-catch-throw.c
> +++ b/gdb/break-catch-throw.c
> @@ -257,7 +257,7 @@ exception_catchpoint::print_it (const bpstat *bs) const
>    bp_temp = disposition == disp_del;
>    uiout->text (bp_temp ? "Temporary catchpoint "
>  		       : "Catchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text ((kind == EX_EVENT_THROW ? " (exception thrown), "
>  		: (kind == EX_EVENT_CATCH ? " (exception caught), "
>  		   : " (exception rethrown), ")));
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index ed932a19ed7..c89c800f32f 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -820,6 +820,19 @@ get_breakpoint (int num)
>    return nullptr;
>  }
>  
> 
> +/* Return TRUE if NUM refer to an existing breakpoint that has
> +   multiple code locations.  */
> +
> +static bool
> +has_multiple_locations (int num)
> +{
> +  for (breakpoint *b : all_breakpoints ())
> +    if (b->number == num)
> +      return b->loc != nullptr && b->loc->next != nullptr;
> +
> +  return false;
> +}
> +
>  \f
>  
> 
>  /* Mark locations as "conditions have changed" in case the target supports
> @@ -4451,15 +4464,7 @@ bpstat_explains_signal (bpstat *bsp, enum gdb_signal sig)
>    return false;
>  }
>  
> 
> -/* Put in *NUM the breakpoint number of the first breakpoint we are
> -   stopped at.  *BSP upon return is a bpstat which points to the
> -   remaining breakpoints stopped at (but which is not guaranteed to be
> -   good for anything but further calls to bpstat_num).
> -
> -   Return 0 if passed a bpstat which does not indicate any breakpoints.
> -   Return -1 if stopped at a breakpoint that has been deleted since
> -   we set it.
> -   Return 1 otherwise.  */
> +/* See breakpoint.h.  */
>  
> 
>  int
>  bpstat_num (bpstat **bsp, int *num)
> @@ -4481,6 +4486,57 @@ bpstat_num (bpstat **bsp, int *num)
>    return 1;
>  }
>  
> 
> +/* See breakpoint.h  */
> +
> +int
> +bpstat_locno (const bpstat *bs)
> +{
> +  const struct breakpoint *b = bs->breakpoint_at;
> +  const struct bp_location *bl = bs->bp_location_at.get ();
> +
> +  int locno = 0;
> +
> +  if (b != nullptr && b->loc->next != nullptr)
> +    {
> +      const bp_location *bl_i;
> +
> +      for (bl_i = b->loc;
> +	   bl_i != bl && bl_i->next != nullptr;
> +	   bl_i = bl_i->next)
> +	locno++;
> +
> +      if (bl_i == bl)
> +	locno++;
> +      else
> +	{
> +	  warning (_("location number not found for breakpoint %d address %s."),
> +		   b->number, paddress (bl->gdbarch, bl->address));
> +	  locno = 0;
> +	}
> +    }
> +
> +  return locno;
> +}
> +
> +/* See breakpoint.h.  */
> +
> +void
> +print_num_locno (const bpstat *bs, struct ui_out *uiout)
> +{
> +  struct breakpoint *b = bs->breakpoint_at;
> +
> +  if (b == nullptr)
> +    uiout->text (_("deleted breakpoint"));
> +  else
> +    {
> +      uiout->field_signed ("bkptno", b->number);
> +
> +      int locno = bpstat_locno (bs);
> +      if (locno != 0)
> +	uiout->message (".%pF", signed_field ("locno", locno));
> +    }
> +}
> +
>  /* See breakpoint.h.  */
>  
> 
>  void
> @@ -9176,7 +9232,7 @@ ranged_breakpoint::print_it (const bpstat *bs) const
>  		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
> @@ -11610,12 +11666,13 @@ ordinary_breakpoint::print_it (const bpstat *bs) const
>  			   async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> +
>    if (bp_temp)
> -    uiout->message ("Temporary breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Temporary breakpoint ");
>    else
> -    uiout->message ("Breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Breakpoint ");
> +  print_num_locno (bs, uiout);
> +  uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
>  }
> @@ -13220,9 +13277,13 @@ enable_disable_command (const char *args, int from_tty, bool enable)
>  	  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)
> +	      && (bp_loc_range.first == 0
> +		  || (bp_loc_range.first == 1
> +		      && bp_num_range.first == bp_num_range.second
> +		      && !has_multiple_locations (bp_num_range.first))))
>  	    {
> -	      /* Handle breakpoint ids with formats 'x' or 'x-z'.  */
> +	      /* Handle breakpoint ids with formats 'x' or 'x-z'
> +		 or 'y.1' where y has only one code location.  */
>  	      map_breakpoint_number_range (bp_num_range,
>  					   enable
>  					   ? enable_breakpoint
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 566f1285e46..96d61ef5427 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -1231,6 +1231,20 @@ extern enum print_stop_action bpstat_print (bpstat *, int);
>     Return 1 otherwise.  */
>  extern int bpstat_num (bpstat **, int *);
>  
> 
> +/* If BS indicates a breakpoint and this breakpoint has several code locations,
> +   return the location number of BS, otherwise return 0.  */
> +
> +extern int bpstat_locno (const bpstat *bs);
> +
> +/* Print BS breakpoint number optionally followed by a . and breakpoint locno.
> +
> +   For a breakpoint with only one code location, outputs the signed field
> +   "bkptno" breakpoint number of BS (as returned by bpstat_num).
> +   If BS has several code locations, outputs a '.' character followed by
> +   the signed field "locno" (as returned by bpstat_locno).  */
> +
> +extern void print_num_locno (const bpstat *bs, struct ui_out *);
> +
>  /* Perform actions associated with the stopped inferior.  Actually, we
>     just use this for breakpoint commands.  Perhaps other actions will
>     go here later, but this is executed at a late time (from the
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 434add3a663..391b81f8863 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -4338,9 +4338,65 @@ are operated on.
>  @cindex latest breakpoint
>  Breakpoints are set with the @code{break} command (abbreviated
>  @code{b}).  The debugger convenience variable @samp{$bpnum} records the
> -number of the breakpoint you've set most recently; see @ref{Convenience
> -Vars,, Convenience Variables}, for a discussion of what you can do with
> -convenience variables.
> +number of the breakpoint you've set most recently:
> +@smallexample
> +(gdb) b main
> +Breakpoint 1 at 0x11c6: file zeoes.c, line 24.
> +(gdb) p $bpnum
> +$1 = 1
> +@end smallexample
> +
> +A breakpoint may be mapped to multiple code locations for example with
> +inlined functions, Ada generics, C@t{++} templates or overloaded function names.
> +@value{GDBN} then indicates the number of code locations in the breakpoint
> +command output:
> +@smallexample
> +(gdb) b some_func
> +Breakpoint 2 at 0x1179: some_func. (3 locations)
> +(gdb) p $bpnum
> +$2 = 2
> +(gdb)
> +@end smallexample
> +
> +@vindex $bkptno@r{, convenience variable}
> +@vindex $locno@r{, convenience variable}
> +When your program stops on a breakpoint, the convenience variables
> +@samp{$bkptno} and @samp{$locno} are respectively set to the number of
> +the encountered breakpoint and the number of the breakpoint's code location:
> +@smallexample
> +Thread 1 "zeoes" hit Breakpoint 2.1, some_func () at zeoes.c:8
> +8	  printf("some func\n");
> +(gdb) p $bkptno
> +$5 = 2
> +(gdb) p $locno
> +$6 = 1
> +(gdb)
> +@end smallexample
> +
> +Note that @samp{$bkptno} and @samp{$bpnum} are not equivalent:
> +@samp{$bkptno} is set to the breakpoint number @b{last hit}, while
> +@samp{$bpnum} is set to the breakpoint number @b{last set}.
> +
> +
> +If the encountered breakpoint has only one code location, @samp{$locno} is set
> +to 1:
> +@smallexample
> +Breakpoint 1, main (argc=1, argv=0x7fffffffe018) at zeoes.c:24
> +24	  if (argc > 1)
> +(gdb) p $bkptno
> +$3 = 1
> +(gdb) p $locno
> +$4 = 1
> +(gdb)
> +@end smallexample
> +
> +The @samp{$bkptno} and @samp{$locno} variables can typically be used
> +in a breakpoint command list.
> +(@pxref{Break Commands, ,Breakpoint Command Lists}). For example, as
> +part of the breakpoint command list, you can disable completely the
> +encountered breakpoint using @samp{disable $bkptno} or disable the
> +specific encountered breakpoint location using @samp{disable
> +$bkptno.$locno}.
>  
> 
>  @table @code
>  @item break @var{locspec}
> @@ -5739,6 +5795,13 @@ Expressions}).
>  Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
>  disabled within a @var{command-list}.
>  
> 
> +Inside a command list, you can use the command
> +@kbd{disable $bkptno} to disable the encountered breakpoint.
> +
> +If your breakpoint has several code locations, the command
> +@kbd{disable $bkptno.$locno} will disable the specific breakpoint code
> +location encountered.
> +
>  You can use breakpoint commands to start your program up again.  Simply
>  use the @code{continue} command, or @code{step}, or any other command
>  that resumes execution.
> @@ -32570,6 +32633,20 @@ line="13",arch="i386:x86_64"@}
>  (gdb)
>  @end smallexample
>  
> 
> +For a @samp{breakpoint-hit} stopped reason, when the breakpoint
> +encountered has multiple locations, the field @samp{bkptno} is
> +followed by the field @samp{locno}.
> +
> +@smallexample
> +-exec-continue
> +^running
> +(gdb)
> +@@Hello world
> +*stopped,reason="breakpoint-hit",disp="keep",bkptno="2",locno="3",frame=@{
> +func="foo",args=[],file="hello.c",fullname="/home/foo/bar/hello.c",
> +line="13",arch="i386:x86_64"@}
> +(gdb)
> +@end smallexample
>  
> 
>  @subheading The @code{-exec-finish} Command
>  @findex -exec-finish
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 02c98b50c8c..e5ad062a914 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -8494,7 +8494,21 @@ print_stop_location (const target_waitstatus &ws)
>       LOCATION: Print only location
>       SRC_AND_LOC: Print location and source line.  */
>    if (do_frame_printing)
> -    print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    {
> +      if (tp->control.stop_bpstat != nullptr)
> +	{
> +	  const struct breakpoint *b = tp->control.stop_bpstat->breakpoint_at;
> +
> +	  if (b != nullptr)
> +	    {
> +	      int locno = bpstat_locno (tp->control.stop_bpstat);
> +	      set_internalvar_integer (lookup_internalvar ("bkptno"), b->number);
> +	      set_internalvar_integer (lookup_internalvar ("locno"),
> +				       (locno > 0 ? locno : 1));
> +	    }
> +	}
> +      print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    }
>  }
>  
> 
>  /* See infrun.h.  */
> diff --git a/gdb/testsuite/gdb.ada/bp_inlined_func.exp b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> index 076e8c2425f..3f94c163819 100644
> --- a/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> +++ b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> @@ -42,7 +42,7 @@ gdb_test "break read_small" \
>  for {set i 0} {$i < 4} {incr i} {
>      with_test_prefix "iteration $i" {
>  	gdb_test "continue" \
> -	    "Breakpoint $decimal, b\\.read_small \\(\\).*" \
> +	    "Breakpoint $bkptno_num_re, b\\.read_small \\(\\).*" \
>  	    "stopped in read_small"
>      }
>  }
> diff --git a/gdb/testsuite/gdb.ada/operator_bp.exp b/gdb/testsuite/gdb.ada/operator_bp.exp
> index 655e7af479f..e3928419ed6 100644
> --- a/gdb/testsuite/gdb.ada/operator_bp.exp
> +++ b/gdb/testsuite/gdb.ada/operator_bp.exp
> @@ -56,7 +56,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to \"$op\""
>  }
>  
> 
> @@ -86,7 +86,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to ops.\"$op\""
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> index b540df973a3..742315178e3 100644
> --- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> +++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> @@ -140,11 +140,11 @@ with_test_prefix "scenario 1" {
>      gdb_run_cmd
>  
> 
>      # Check our conditional breakpoints.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> @@ -208,11 +208,11 @@ with_test_prefix "scenario 2" {
>      gdb_run_cmd
>  
> 
>      # Check that we hit enabled locations only.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> diff --git a/gdb/testsuite/gdb.base/ctxobj.exp b/gdb/testsuite/gdb.base/ctxobj.exp
> index 9c010f54d79..0b589a7d6e6 100644
> --- a/gdb/testsuite/gdb.base/ctxobj.exp
> +++ b/gdb/testsuite/gdb.base/ctxobj.exp
> @@ -67,9 +67,16 @@ gdb_test "break ctxobj-f.c:$bp_location" \
>           "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
>           "break in get_version functions"
>  
> 
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_1 \\(\\).*" \
> -         "continue to get_version_1"
> +global expect_out
> +set test "continue to get_version_1"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_1 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  # Try printing "this_version_num".  There are two global variables
>  # with that name, and some systems such as GNU/Linux merge them
> @@ -100,10 +107,15 @@ gdb_test "print this_version_num == v" \
>          "print libctxobj1's this_version_num from symtab"
>  
> 
>  # Do the same, but from get_version_2.
> -
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_2 \\(\\).*" \
> -         "continue to get_version_2"
> +set test "continue to get_version_2"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_2 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  gdb_test "print this_version_num == v" \
>           " = 1" \
> diff --git a/gdb/testsuite/gdb.base/ena-dis-br.exp b/gdb/testsuite/gdb.base/ena-dis-br.exp
> index 24925cf7185..04b3f134b44 100644
> --- a/gdb/testsuite/gdb.base/ena-dis-br.exp
> +++ b/gdb/testsuite/gdb.base/ena-dis-br.exp
> @@ -67,14 +67,21 @@ gdb_test "info break $bp" \
>  # See the comments in condbreak.exp for "run until breakpoint at
>  # marker1" for an explanation of the xfail below.
>  set test "continue to break marker1"
> +set bpno 0
>  gdb_test_multiple "continue" "$test" {
> -    -re "Breakpoint \[0-9\]*, marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	pass "$test"
>      }
> -    -re "Breakpoint \[0-9\]*, $hex in marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), $hex in marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	xfail "$test"
>      }
>  }
> +# Verify the $bkptno convenience variable is equal to the hit bpno.
> +gdb_test "print \$bkptno" " = $bpno" "$test \$bkptno is $bpno"
> +# Verify the $locno is 1, as there is only one code location.
> +gdb_test "print \$locno" " = 1" "$test \$locno is 1"
>  
> 
>  gdb_test_no_output "delete $bp" "delete break marker1"
>  
> 
> @@ -359,7 +366,8 @@ with_test_prefix "4th breakpoint" {
>  }
>  
> 
>  # Perform tests for disable/enable commands on multiple
> -# locations and breakpoints.
> +# code locations and breakpoints.  If a breakpoint has only one code location,
> +# enable/disable num  and enable/disable num.1 should be equivalent.
>  #
>  # WHAT - the command to test (disable/enable).
>  #
> @@ -372,7 +380,7 @@ proc test_ena_dis_br { what } {
>      global b3
>      global b4
>      global gdb_prompt
> -    
> +
>      # OPPOS    - the command opposite to WHAT.
>      # WHAT_RES - whether breakpoints are expected to end
>      #            up enabled or disabled.
> @@ -395,13 +403,13 @@ proc test_ena_dis_br { what } {
>  	set p2 "pass"
>      }
>  
> 
> -    # Now enable(disable) $b.1 $b2.1.
> +    # Now enable(disable) $b1.1 $b2.1.
>      gdb_test_no_output "$what $b1.1 $b2.1" "$what \$b1.1 \$b2.1"
>      set test1 "${what}d \$b1.1 and \$b2.1"
>  
> 
>      # Now $b1.1 and $b2.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -       -re "(${b1}.1)(\[^\n\r\]*)( n.*)(${b2}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +       -re "(${b1})(\[^\n\r\]*)( n.*)(${b2})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> @@ -420,19 +428,16 @@ proc test_ena_dis_br { what } {
>         "${what}d \$b1"
>  
> 
>      gdb_test_no_output "$oppos $b3" "$oppos \$b3"
> +    # Now $b4 $b3 should be enabled(disabled)
> +    set test1 "${what}d \$b4 and \$b3"
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $oppos_res.*).*(${b4})(\[^\n\r\]*)( $oppos_res.*)" "$test1"
> +
>      gdb_test_no_output "$what $b4 $b3.1" "$what \$b4 \$b3.1"
> -    set test1 "${what}d \$b4 and \$b3.1,remain ${oppos}d \$b3"
> +    set test1 "${what}d \$b4 and \$b3.1, changing \$b3"
> +
> +    # Now $b4 $b3 should be enabled(disabled)
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $what_res.*).*(${b4})(\[^\n\r\]*)( $what_res.*)" "$test1"
>  
> 
> -    # Now $b4 $b3.1 should be enabled(disabled) and
> -    # $b3 should remain disabled(enabled).
> -    gdb_test_multiple "info break" "$test1" {
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b3}.1)(\[^\n\r\]*)( n.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p1 "$test1"
> -       }
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p2 "$test1"
> -       }
> -    }
>  
> 
>      # Now enable(disable) '$b4.1 fooobaar'.  This should error on
>      # fooobaar.
> @@ -443,7 +448,7 @@ proc test_ena_dis_br { what } {
>  
> 
>      # $b4.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -        -re "(${b4}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +        -re "(${b4})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.base/foll-exec-mode.exp b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> index 918f3e4fd5f..cb6d975a767 100644
> --- a/gdb/testsuite/gdb.base/foll-exec-mode.exp
> +++ b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> @@ -99,7 +99,7 @@ proc do_catch_exec_test { } {
>  # before re-running.
>  
> 
>  proc do_follow_exec_mode_tests { mode cmd infswitch } {
> -    global binfile srcfile srcfile2 testfile testfile2
> +    global binfile srcfile srcfile2 testfile testfile2 bkptno_numopt_re
>      global gdb_prompt
>  
> 
>      with_test_prefix "$mode,$cmd,$infswitch" {
> @@ -125,7 +125,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  	# Set up the output we expect to see after we execute past the exec.
>  	#
>  	set execd_line [gdb_get_line_number "after-exec" $srcfile2]
> -	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint .,.*${srcfile2}:${execd_line}.*$gdb_prompt $"
> +	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint ${bkptno_numopt_re},.*${srcfile2}:${execd_line}.*$gdb_prompt $"
>  
> 
>  	# Set a breakpoint after the exec call if we aren't single-stepping
>  	# past it.
> @@ -189,7 +189,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  		send_gdb "y\n"
>  		exp_continue
>  	    }
> -	    -re "Starting program: .*$expected_inf.*Breakpoint .,.*\r\n$gdb_prompt $" {
> +	    -re "Starting program: .*$expected_inf.*Breakpoint $bkptno_numopt_re,.*\r\n$gdb_prompt $" {
>  		pass $test
>  	    }
>  	}
> diff --git a/gdb/testsuite/gdb.base/pie-fork.exp b/gdb/testsuite/gdb.base/pie-fork.exp
> index efc357d39a2..19e9d3a5537 100644
> --- a/gdb/testsuite/gdb.base/pie-fork.exp
> +++ b/gdb/testsuite/gdb.base/pie-fork.exp
> @@ -54,10 +54,10 @@ proc_with_prefix test_detach_on_fork_follow_child {} {
>  proc_with_prefix test_no_detach_on_fork {} {
>      setup_test "off"
>  
> 
> -    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2.1, break_here.*" \
>  	     "continue from thread 1.1"
>      gdb_test "thread 2.1"
> -    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2.2, break_here.*" \
>  	     "continue from thread 2.1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/step-over-exit.exp b/gdb/testsuite/gdb.base/step-over-exit.exp
> index f8bd99980fe..575319c564c 100644
> --- a/gdb/testsuite/gdb.base/step-over-exit.exp
> +++ b/gdb/testsuite/gdb.base/step-over-exit.exp
> @@ -91,7 +91,7 @@ delete_breakpoints
>  
> 
>  gdb_test "break marker"
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_num_re, .*" \
>      "continue to marker, first time"
>  
> 
>  # Step 2, create a breakpoint which evaluates false, and force it
> @@ -120,5 +120,5 @@ gdb_test "inferior 1" ".*Switching to inferior 1.*" \
>  # Switch back to the parent process, continue to the marker to
>  # test GDBserver's state is still correct.
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_numopt_re, .*" \
>      "continue to marker, second time"
> diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
> index 47a2a5dcb7c..fa098602c31 100644
> --- a/gdb/testsuite/gdb.cp/mb-inline.exp
> +++ b/gdb/testsuite/gdb.cp/mb-inline.exp
> @@ -46,7 +46,7 @@ gdb_test "info break" \
>      "\[\r\n\]1\.1.* y .* at .*$hdrfile:$bp_location.*\[\r\n\]1\.2.* y .* at .*$hdrfile:$bp_location.*"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo \\(i=1\\).*" \
> @@ -59,7 +59,7 @@ gdb_test "continue" \
>  gdb_test_no_output "disable 1.2" "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
>  
> 
>  gdb_test_multiple "info break" "disabled breakpoint 1.2" {
>      -re "1\.2.* n .* at .*$hdrfile:$bp_location.*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
> index 6c988e7335e..0c0d46fcb7a 100644
> --- a/gdb/testsuite/gdb.cp/mb-templates.exp
> +++ b/gdb/testsuite/gdb.cp/mb-templates.exp
> @@ -42,7 +42,7 @@ gdb_run_cmd
>  
> 
>  set test "initial condition: run to breakpoint"
>  gdb_test_multiple "" $test {
> -    -re "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
> +    -re "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
>  	pass $test
>  	break
>      }
> @@ -67,7 +67,7 @@ gdb_test_no_output {condition $bpnum i==1} \
>      "separate condition: set condition"
>      
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo<double> \\(i=1\\).*" \
> @@ -79,7 +79,7 @@ gdb_test "continue" \
>  gdb_test_no_output {disable $bpnum.1} "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
>  
> 
>  # Try disabling entire breakpoint
>  gdb_test_no_output {enable $bpnum.1} "disabling location: enable"
> diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
> index 06adf82ecbb..0ed9eae055b 100644
> --- a/gdb/testsuite/gdb.cp/ovldbreak.exp
> +++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
> @@ -380,7 +380,7 @@ gdb_test "info break" $bptable "breakpoint info (after setting on all)"
>  
> 
>  # Run through each breakpoint.
>  proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
> -    global gdb_prompt hex decimal srcfile
> +    global gdb_prompt hex decimal srcfile bkptno_num_re
>  
> 
>      if {$argument == ""} {
>          set actuals ""
> @@ -398,11 +398,11 @@ proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
>      }
>  
> 
>      gdb_test_multiple "continue" "continue to bp overloaded : $argtype" {
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              pass "continue to bp overloaded : $argtype"
>          }
>  
> 
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              if $might_kfail {
>                  kfail "c++/8130" "continue to bp overloaded : $argtype"
>              } else {
> diff --git a/gdb/testsuite/gdb.gdb/python-helper.exp b/gdb/testsuite/gdb.gdb/python-helper.exp
> index 6db8bf0df50..30eb6038f3a 100644
> --- a/gdb/testsuite/gdb.gdb/python-helper.exp
> +++ b/gdb/testsuite/gdb.gdb/python-helper.exp
> @@ -49,7 +49,7 @@ gdb_exit
>  # The main test.  This is called by the self-test framework once GDB
>  # has been started on a copy of itself.
>  proc test_python_helper {} {
> -    global py_helper_script decimal hex gdb_prompt
> +    global py_helper_script decimal hex gdb_prompt bkptno_numopt_re
>      global inferior_spawn_id
>  
> 
>      # Source the python helper script.  This script registers the
> @@ -233,7 +233,7 @@ proc test_python_helper {} {
>      # GDB stopping at the value_print breakpoint again.
>      send_inferior "ptype global_c\n"
>      gdb_test_multiple "" "hit breakpoint in outer gdb again" {
> -	-re "Breakpoint $decimal, c_print_type .*\\(outer-gdb\\) $" {
> +	-re "Breakpoint $bkptno_numopt_re, c_print_type .*\\(outer-gdb\\) $" {
>  	    pass $gdb_test_name
>  	}
>      }
> diff --git a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> index 19ccbe85e04..c080955049c 100644
> --- a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> +++ b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> @@ -69,7 +69,7 @@ if { $use_second_inferior } {
>  	"\\^running.*" \
>  	"run inferior 2"
>  
> 
> -    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\""} \
> +    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\"" "locno=\"[0-9]+\""} \
>  	"inferior i2 stops at all_threads_started"
>  
> 
>      mi_send_resuming_command "exec-continue --thread-group i2" \
> diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> index d78c96ddef1..9eec083068b 100644
> --- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> +++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> @@ -307,8 +307,13 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  	    # Consume MI event output.
>  	    with_spawn_id $mi_spawn_id {
> -		mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> -		    "$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		if { $inf == 1 } {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		} else {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} "stop at breakpoint in main"
> +		}
>  	    }
>  
> 
>  	    if { $mode == "all-stop" } {
> @@ -330,9 +335,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		    # Consume MI output.
>  		    with_spawn_id $mi_spawn_id {
> -			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			    "thread $inf.$thread stops MI"
> +			if { $inf == 1} {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +				"thread $inf.$thread stops MI"
> +			} else {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +				"thread $inf.$thread stops MI"
> +			}
>  		    }
>  		}
>  
> 
> @@ -359,9 +370,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		# Consume MI output.
>  		with_spawn_id $mi_spawn_id {
> -		    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			"thread $inf.2 stops MI"
> +		    if { $inf == 1} {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +			    "thread $inf.2 stops MI"
> +		    } else {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +			    "thread $inf.2 stops MI"
> +		    }
>  		}
>  	    }
>  	}
> @@ -434,7 +451,7 @@ proc_with_prefix test_setup { mode } {
>  
> 
>  	with_spawn_id $mi_spawn_id {
>  	    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" "$decimal" \
> -		{"" "disp=\"del\""} "main stop"
> +		{"" "disp=\"del\"" "locno=\"[0-9]+\""} "main stop"
>  	}
>  
> 
>  	# Consume CLI output.
> diff --git a/gdb/testsuite/gdb.multi/multi-arch-exec.exp b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> index a1496fb5571..dfdb746c65e 100644
> --- a/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> +++ b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> @@ -148,6 +148,7 @@ proc build_executables { first_arch } {
>  }
>  
> 
>  proc do_test { first_arch mode selected_thread } {
> +        global bkptno_numopt_re
>  	set from_exec "$first_arch-multi-arch-exec"
>  
> 
>  	clean_restart ${from_exec}
> @@ -169,7 +170,7 @@ proc do_test { first_arch mode selected_thread } {
>  
> 
>  	# Test that GDB updates the target description / arch successfuly
>  	# after the exec.
> -	gdb_test "continue" "Breakpoint 2, main.*" "continue across exec that changes architecture"
> +	gdb_test "continue" "Breakpoint $bkptno_numopt_re, main.*" "continue across exec that changes architecture"
>  }
>  
> 
>  # Test both arch1=>arch2 and arch2=>arch1.
> diff --git a/gdb/testsuite/gdb.multi/run-only-second-inf.exp b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> index fec2575f904..b94689d0bfa 100644
> --- a/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> +++ b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> @@ -46,5 +46,5 @@ gdb_load $binfile
>  if {[gdb_start_cmd] < 0} {
>      fail "start the second inf"
>  } else {
> -    gdb_test "" ".*reakpoint ., main .*${srcfile}.*" "start the second inf"
> +    gdb_test "" ".*reakpoint $bkptno_numopt_re, main .*${srcfile}.*" "start the second inf"
>  }
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> index cbccba19d12..3c079facced 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> @@ -27,7 +27,7 @@ if {[build_executable "failed to build" $testfile $srcfile {debug}]} {
>  # child.  Can be either "kill", "detach", or "exit" (to continue it to
>  # normal exit).
>  proc do_test {dispose} {
> -    global binfile
> +    global binfile bkptno_numopt_re
>  
> 
>      clean_restart $binfile
>  
> 
> @@ -77,7 +77,7 @@ proc do_test {dispose} {
>      #  Command aborted.
>      #  (gdb)
>      #
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker .*" \
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker .*" \
>  	"continue in inferior 1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi.exp b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> index e4329dca6c2..0fc1bee762f 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> @@ -84,11 +84,11 @@ if [skip_hw_watchpoint_multi_tests] {
>  	"Hardware access \\(read/write\\) watchpoint \[0-9\]+: c\r\n\r\nOld value = 0\r\nNew value = 3\r\n.*" \
>  	"catch c on inferior 2"
>  
> 
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 2"
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 2"
>  
> 
>      gdb_test "inferior 1" "witching to inferior 1 .*" "switch back to inferior 1 again"
>  
> 
>      gdb_test "continue" "Hardware access \\(read/write\\) watchpoint \[0-9\]+: b\r\n\r\nOld value = 0\r\nNew value = 2\r\n.*" "catch b on inferior 1"
>  }
>  
> 
> -gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 1"
> +gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 1"
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 402450152ac..5e4c793598e 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -227,6 +227,14 @@ set inferior_exited_re "(?:\\\[Inferior \[0-9\]+ \\(\[^\n\r\]*\\) exited)"
>  # E.g., $1, $2, etc.
>  set valnum_re "\\\$$decimal"
>  
> 
> +# A regular expression that matches a breakpoint hit with a breakpoint
> +# having several code locations.
> +set bkptno_num_re "$decimal\\.$decimal"
> +
> +# A regular expression that matches a breakpoint hit
> +# with one or several code locations.
> +set bkptno_numopt_re "($decimal\\.$decimal|$decimal)"
> +
>  ### Only procedures should come after this point.
>  
> 
>  #
> @@ -662,6 +670,7 @@ proc gdb_breakpoint { linespec args } {
>  
> 
>  proc runto { linespec args } {
>      global gdb_prompt
> +    global bkptno_numopt_re
>      global decimal
>  
> 
>      delete_breakpoints
> @@ -699,7 +708,7 @@ proc runto { linespec args } {
>  	    }
>  	    return 1
>  	}
> -	-re "Breakpoint \[0-9\]*, \[0-9xa-f\]* in .*$gdb_prompt $" { 
> +	-re "Breakpoint $bkptno_numopt_re, \[0-9xa-f\]* in .*$gdb_prompt $" {
>  	    if { $print_pass } {
>  		pass $test_name
>  	    }
> diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
> index e578a7e6f9b..ea66fdcabf8 100644
> --- a/gdb/testsuite/lib/mi-support.exp
> +++ b/gdb/testsuite/lib/mi-support.exp
> @@ -1195,11 +1195,11 @@ proc mi_detect_async {} {
>  # filename of a file without debug info.  ARGS should not include [] the
>  # list of argument is enclosed in, and other regular expressions should
>  # not include quotes.
> -# If EXTRA is a list of one element, it's the regular expression
> +# EXTRA can be a list of one, two or three elements.
> +# The first element is the regular expression
>  # for output expected right after *stopped, and before GDB prompt.
> -# If EXTRA is a list of two elements, the first element is for
> -# output right after *stopped, and the second element is output
> -# right after reason field.  The regex after reason should not include
> +# The third element is the regulation expression for the locno
> +# right after bkptno field.  The locno regex should not include
>  # the comma separating it from the following fields.
>  #
>  # When we fail to match output at all, -1 is returned.  If FILE does
> @@ -1224,7 +1224,14 @@ proc mi_expect_stop { reason func args file line extra test } {
>  
> 
>      set after_stopped ""
>      set after_reason ""
> -    if { [llength $extra] == 2 } {
> +    set locno ""
> +    if { [llength $extra] == 3 } {
> +	set after_stopped [lindex $extra 0]
> +	set after_reason [lindex $extra 1]
> +	set after_reason "${after_reason},"
> +	set locno [lindex $extra 2]
> +	set locno "${locno},"
> +    } elseif { [llength $extra] == 2 } {
>  	set after_stopped [lindex $extra 0]
>  	set after_reason [lindex $extra 1]
>  	set after_reason "${after_reason},"
> @@ -1298,10 +1305,12 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set ebn ""
>      if { $reason == "breakpoint-hit" } {
>  	set bn {bkptno="[0-9]+",}
> +	set bn "${bn}${locno}"
>      } elseif { $reason == "solib-event" } {
>  	set bn ".*"
>      } elseif { $reason == "exception-caught" } {
>  	set ebn {bkptno="[0-9]+",}
> +	set ebn "${ebn}${locno}"
>  	set bn ".*"
>  	set reason "breakpoint-hit"
>      }
> @@ -1315,6 +1324,7 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set a $after_reason
>  
> 
>      verbose -log "mi_expect_stop: expecting: \\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
> +
>      gdb_expect {
>  	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
>  	    pass "$test"



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-06-06  9:45 [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno Philippe Waroquiers
                   ` (6 preceding siblings ...)
  2022-08-08  6:52 ` Philippe Waroquiers
@ 2022-08-14 14:08 ` Philippe Waroquiers
  2022-08-21 12:05 ` Philippe Waroquiers
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Philippe Waroquiers @ 2022-08-14 14:08 UTC (permalink / raw)
  To: gdb-patches


Ping ^ 7
(Eli reviewed the doc, Keith did a first review)

Thanks
Philippe

On Mon, 2022-06-06 at 11:45 +0200, Philippe Waroquiers wrote:
> Before this patch, when a breakpoint that has multiple locations is reached,
> GDB printed:
>   Thread 1 "zeoes" hit Breakpoint 1, some_func () at somefunc1.c:5
> 
> This patch changes the message so that bkpt_print_id prints the precise
> encountered breakpoint:
>   Thread 1 "zeoes" hit Breakpoint 1.2, some_func () at somefunc1.c:5
> 
> In mi mode, bkpt_print_id also (optionally) prints a new table field "locno":
>   locno is printed when the breakpoint has more than one location.
> Note that according to the GDB user manual node 'GDB/MI Development and Front
> Ends', it is ok to add new fields without changing the MI version.
> 
> Also, when a breakpoint is reached, the convenience variables
> $bkptno and $locno are set to the encountered breakpoint number
> and location number.
> 
> $bkptno and $locno can a.o. be used in the command list of a breakpoint,
> to disable the specific encountered breakpoint, e.g.
>    disable $bkptno.$locno
> 
> In case the breakpoint has only one location, $locno is still set to
> the value 1, so as to allow a command such as:
>   disable $bkptno.$locno
> even when the breakpoint has only one location.
> 
> This also fixes a strange behaviour: when a breakpoint X has only
> one location,
>   enable|disable X.1
> is accepted but transforms the breakpoint in a multiple locations
> breakpoint having only one location.
> 
> The changes in RFA v3 handle the additional comments of Eli:
>  GDB/NEW:
>   - Use max 80-column
>   - Use 'code location' instead of 'location'.
>   - Fix typo $bkpno
>   - Ensure that disable $bkptno and disable $bkptno.$locno have
>     each their explanation inthe example
>   - Reworded the 'breakpoint-hit' paragraph.
>  gdb.texinfo:
>   - Use 'code location' instead of 'location'.
>   - Add a note to clarify the distinction between $bkptno and $bpnum.
>   - Use @kbd instead of examples with only one command.
> 
> Compared to RFA v1, the changes in v2 handle the comments given by
> Keith Seitz and Eli Zaretskii:
>   - Use %s for the result of paddress
>   - Use bkptno_numopt_re instead of 2 different -re cases
>   - use C@t{++}
>   - Add index entries for $bkptno and $locno
>   - Added an example for "locno" in the mi interface
>   - Added examples in the Break command manual.
> ---
>  gdb/NEWS                                      | 21 +++++
>  gdb/ada-lang.c                                |  2 +-
>  gdb/break-catch-syscall.c                     |  2 +-
>  gdb/break-catch-throw.c                       |  2 +-
>  gdb/breakpoint.c                              | 93 +++++++++++++++----
>  gdb/breakpoint.h                              | 14 +++
>  gdb/doc/gdb.texinfo                           | 83 ++++++++++++++++-
>  gdb/infrun.c                                  | 16 +++-
>  gdb/testsuite/gdb.ada/bp_inlined_func.exp     |  2 +-
>  gdb/testsuite/gdb.ada/operator_bp.exp         |  4 +-
>  .../gdb.base/condbreak-multi-context.exp      |  8 +-
>  gdb/testsuite/gdb.base/ctxobj.exp             | 26 ++++--
>  gdb/testsuite/gdb.base/ena-dis-br.exp         | 41 ++++----
>  gdb/testsuite/gdb.base/foll-exec-mode.exp     |  6 +-
>  gdb/testsuite/gdb.base/pie-fork.exp           |  4 +-
>  gdb/testsuite/gdb.base/step-over-exit.exp     |  4 +-
>  gdb/testsuite/gdb.cp/mb-inline.exp            |  4 +-
>  gdb/testsuite/gdb.cp/mb-templates.exp         |  6 +-
>  gdb/testsuite/gdb.cp/ovldbreak.exp            |  6 +-
>  gdb/testsuite/gdb.gdb/python-helper.exp       |  4 +-
>  .../gdb.mi/interrupt-thread-group.exp         |  2 +-
>  .../gdb.mi/user-selected-context-sync.exp     | 35 +++++--
>  gdb/testsuite/gdb.multi/multi-arch-exec.exp   |  3 +-
>  .../gdb.multi/run-only-second-inf.exp         |  2 +-
>  .../gdb.multi/watchpoint-multi-exit.exp       |  4 +-
>  gdb/testsuite/gdb.multi/watchpoint-multi.exp  |  4 +-
>  gdb/testsuite/lib/gdb.exp                     | 11 ++-
>  gdb/testsuite/lib/mi-support.exp              | 20 +++-
>  28 files changed, 335 insertions(+), 94 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 960f90b4387..a5602deee2b 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -34,6 +34,21 @@
>       whitespace from each line before using the string as the help
>       output.
>  
> 
> +* When a breakpoint with multiple code locations is hit, GDB now prints
> +  the code location using the syntax <breakpoint_number>.<location_number>
> +  such as in:
> +     Thread 1 "zeoes" hit Breakpoint 2.3, some_func () at zeoes.c:8
> +
> +* When a breakpoint is hit, GDB now sets the convenience variables $bkptno and
> +  $locno to the hit breakpoint number and code location number.
> +  This allows to disable the last hit breakpoint using
> +     (gdb) disable $bkptno
> +   or disable only the specific breakpoint code location using
> +     (gdb) disable $bkptno.$locno
> +  These commands can be used inside the command list of a breakpoint to
> +  automatically disable the just encountered breakpoint (or the just
> +  encountered specific breakpoint code location).
> +
>  * New commands
>  
> 
>  maintenance set ignore-prologue-end-flag on|off
> @@ -50,6 +65,12 @@ maintenance info line-table
>    entry corresponds to an address where a breakpoint should be placed
>    to be at the first instruction past a function's prologue.
>  
> 
> +* MI changes
> +
> + ** The async record stating the stopped reason 'breakpoint-hit' now
> +    contains an optional field locno giving the code location number
> +    when the breakpoint has multiple code locations.
> +
>  * Python API
>  
> 
>    ** New function gdb.format_address(ADDRESS, PROGSPACE, ARCHITECTURE),
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 6ab01fd27d4..bbae76f39ac 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -12348,7 +12348,7 @@ ada_catchpoint::print_it (const bpstat *bs) const
>  
> 
>    uiout->text (disposition == disp_del
>  	       ? "\nTemporary catchpoint " : "\nCatchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    /* ada_exception_name_addr relies on the selected frame being the
> diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
> index 06d48466de7..82229de33f7 100644
> --- a/gdb/break-catch-syscall.c
> +++ b/gdb/break-catch-syscall.c
> @@ -218,7 +218,7 @@ syscall_catchpoint::print_it (const bpstat *bs) const
>  						: EXEC_ASYNC_SYSCALL_RETURN));
>        uiout->field_string ("disp", bpdisp_text (b->disposition));
>      }
> -  uiout->field_signed ("bkptno", b->number);
> +  print_num_locno (bs, uiout);
>  
> 
>    if (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY)
>      uiout->text (" (call to syscall ");
> diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
> index 66cf80be1c5..5b6f5d9eca1 100644
> --- a/gdb/break-catch-throw.c
> +++ b/gdb/break-catch-throw.c
> @@ -257,7 +257,7 @@ exception_catchpoint::print_it (const bpstat *bs) const
>    bp_temp = disposition == disp_del;
>    uiout->text (bp_temp ? "Temporary catchpoint "
>  		       : "Catchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text ((kind == EX_EVENT_THROW ? " (exception thrown), "
>  		: (kind == EX_EVENT_CATCH ? " (exception caught), "
>  		   : " (exception rethrown), ")));
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index ed932a19ed7..c89c800f32f 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -820,6 +820,19 @@ get_breakpoint (int num)
>    return nullptr;
>  }
>  
> 
> +/* Return TRUE if NUM refer to an existing breakpoint that has
> +   multiple code locations.  */
> +
> +static bool
> +has_multiple_locations (int num)
> +{
> +  for (breakpoint *b : all_breakpoints ())
> +    if (b->number == num)
> +      return b->loc != nullptr && b->loc->next != nullptr;
> +
> +  return false;
> +}
> +
>  \f
>  
> 
>  /* Mark locations as "conditions have changed" in case the target supports
> @@ -4451,15 +4464,7 @@ bpstat_explains_signal (bpstat *bsp, enum gdb_signal sig)
>    return false;
>  }
>  
> 
> -/* Put in *NUM the breakpoint number of the first breakpoint we are
> -   stopped at.  *BSP upon return is a bpstat which points to the
> -   remaining breakpoints stopped at (but which is not guaranteed to be
> -   good for anything but further calls to bpstat_num).
> -
> -   Return 0 if passed a bpstat which does not indicate any breakpoints.
> -   Return -1 if stopped at a breakpoint that has been deleted since
> -   we set it.
> -   Return 1 otherwise.  */
> +/* See breakpoint.h.  */
>  
> 
>  int
>  bpstat_num (bpstat **bsp, int *num)
> @@ -4481,6 +4486,57 @@ bpstat_num (bpstat **bsp, int *num)
>    return 1;
>  }
>  
> 
> +/* See breakpoint.h  */
> +
> +int
> +bpstat_locno (const bpstat *bs)
> +{
> +  const struct breakpoint *b = bs->breakpoint_at;
> +  const struct bp_location *bl = bs->bp_location_at.get ();
> +
> +  int locno = 0;
> +
> +  if (b != nullptr && b->loc->next != nullptr)
> +    {
> +      const bp_location *bl_i;
> +
> +      for (bl_i = b->loc;
> +	   bl_i != bl && bl_i->next != nullptr;
> +	   bl_i = bl_i->next)
> +	locno++;
> +
> +      if (bl_i == bl)
> +	locno++;
> +      else
> +	{
> +	  warning (_("location number not found for breakpoint %d address %s."),
> +		   b->number, paddress (bl->gdbarch, bl->address));
> +	  locno = 0;
> +	}
> +    }
> +
> +  return locno;
> +}
> +
> +/* See breakpoint.h.  */
> +
> +void
> +print_num_locno (const bpstat *bs, struct ui_out *uiout)
> +{
> +  struct breakpoint *b = bs->breakpoint_at;
> +
> +  if (b == nullptr)
> +    uiout->text (_("deleted breakpoint"));
> +  else
> +    {
> +      uiout->field_signed ("bkptno", b->number);
> +
> +      int locno = bpstat_locno (bs);
> +      if (locno != 0)
> +	uiout->message (".%pF", signed_field ("locno", locno));
> +    }
> +}
> +
>  /* See breakpoint.h.  */
>  
> 
>  void
> @@ -9176,7 +9232,7 @@ ranged_breakpoint::print_it (const bpstat *bs) const
>  		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
> @@ -11610,12 +11666,13 @@ ordinary_breakpoint::print_it (const bpstat *bs) const
>  			   async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> +
>    if (bp_temp)
> -    uiout->message ("Temporary breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Temporary breakpoint ");
>    else
> -    uiout->message ("Breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Breakpoint ");
> +  print_num_locno (bs, uiout);
> +  uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
>  }
> @@ -13220,9 +13277,13 @@ enable_disable_command (const char *args, int from_tty, bool enable)
>  	  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)
> +	      && (bp_loc_range.first == 0
> +		  || (bp_loc_range.first == 1
> +		      && bp_num_range.first == bp_num_range.second
> +		      && !has_multiple_locations (bp_num_range.first))))
>  	    {
> -	      /* Handle breakpoint ids with formats 'x' or 'x-z'.  */
> +	      /* Handle breakpoint ids with formats 'x' or 'x-z'
> +		 or 'y.1' where y has only one code location.  */
>  	      map_breakpoint_number_range (bp_num_range,
>  					   enable
>  					   ? enable_breakpoint
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 566f1285e46..96d61ef5427 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -1231,6 +1231,20 @@ extern enum print_stop_action bpstat_print (bpstat *, int);
>     Return 1 otherwise.  */
>  extern int bpstat_num (bpstat **, int *);
>  
> 
> +/* If BS indicates a breakpoint and this breakpoint has several code locations,
> +   return the location number of BS, otherwise return 0.  */
> +
> +extern int bpstat_locno (const bpstat *bs);
> +
> +/* Print BS breakpoint number optionally followed by a . and breakpoint locno.
> +
> +   For a breakpoint with only one code location, outputs the signed field
> +   "bkptno" breakpoint number of BS (as returned by bpstat_num).
> +   If BS has several code locations, outputs a '.' character followed by
> +   the signed field "locno" (as returned by bpstat_locno).  */
> +
> +extern void print_num_locno (const bpstat *bs, struct ui_out *);
> +
>  /* Perform actions associated with the stopped inferior.  Actually, we
>     just use this for breakpoint commands.  Perhaps other actions will
>     go here later, but this is executed at a late time (from the
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 434add3a663..391b81f8863 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -4338,9 +4338,65 @@ are operated on.
>  @cindex latest breakpoint
>  Breakpoints are set with the @code{break} command (abbreviated
>  @code{b}).  The debugger convenience variable @samp{$bpnum} records the
> -number of the breakpoint you've set most recently; see @ref{Convenience
> -Vars,, Convenience Variables}, for a discussion of what you can do with
> -convenience variables.
> +number of the breakpoint you've set most recently:
> +@smallexample
> +(gdb) b main
> +Breakpoint 1 at 0x11c6: file zeoes.c, line 24.
> +(gdb) p $bpnum
> +$1 = 1
> +@end smallexample
> +
> +A breakpoint may be mapped to multiple code locations for example with
> +inlined functions, Ada generics, C@t{++} templates or overloaded function names.
> +@value{GDBN} then indicates the number of code locations in the breakpoint
> +command output:
> +@smallexample
> +(gdb) b some_func
> +Breakpoint 2 at 0x1179: some_func. (3 locations)
> +(gdb) p $bpnum
> +$2 = 2
> +(gdb)
> +@end smallexample
> +
> +@vindex $bkptno@r{, convenience variable}
> +@vindex $locno@r{, convenience variable}
> +When your program stops on a breakpoint, the convenience variables
> +@samp{$bkptno} and @samp{$locno} are respectively set to the number of
> +the encountered breakpoint and the number of the breakpoint's code location:
> +@smallexample
> +Thread 1 "zeoes" hit Breakpoint 2.1, some_func () at zeoes.c:8
> +8	  printf("some func\n");
> +(gdb) p $bkptno
> +$5 = 2
> +(gdb) p $locno
> +$6 = 1
> +(gdb)
> +@end smallexample
> +
> +Note that @samp{$bkptno} and @samp{$bpnum} are not equivalent:
> +@samp{$bkptno} is set to the breakpoint number @b{last hit}, while
> +@samp{$bpnum} is set to the breakpoint number @b{last set}.
> +
> +
> +If the encountered breakpoint has only one code location, @samp{$locno} is set
> +to 1:
> +@smallexample
> +Breakpoint 1, main (argc=1, argv=0x7fffffffe018) at zeoes.c:24
> +24	  if (argc > 1)
> +(gdb) p $bkptno
> +$3 = 1
> +(gdb) p $locno
> +$4 = 1
> +(gdb)
> +@end smallexample
> +
> +The @samp{$bkptno} and @samp{$locno} variables can typically be used
> +in a breakpoint command list.
> +(@pxref{Break Commands, ,Breakpoint Command Lists}). For example, as
> +part of the breakpoint command list, you can disable completely the
> +encountered breakpoint using @samp{disable $bkptno} or disable the
> +specific encountered breakpoint location using @samp{disable
> +$bkptno.$locno}.
>  
> 
>  @table @code
>  @item break @var{locspec}
> @@ -5739,6 +5795,13 @@ Expressions}).
>  Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
>  disabled within a @var{command-list}.
>  
> 
> +Inside a command list, you can use the command
> +@kbd{disable $bkptno} to disable the encountered breakpoint.
> +
> +If your breakpoint has several code locations, the command
> +@kbd{disable $bkptno.$locno} will disable the specific breakpoint code
> +location encountered.
> +
>  You can use breakpoint commands to start your program up again.  Simply
>  use the @code{continue} command, or @code{step}, or any other command
>  that resumes execution.
> @@ -32570,6 +32633,20 @@ line="13",arch="i386:x86_64"@}
>  (gdb)
>  @end smallexample
>  
> 
> +For a @samp{breakpoint-hit} stopped reason, when the breakpoint
> +encountered has multiple locations, the field @samp{bkptno} is
> +followed by the field @samp{locno}.
> +
> +@smallexample
> +-exec-continue
> +^running
> +(gdb)
> +@@Hello world
> +*stopped,reason="breakpoint-hit",disp="keep",bkptno="2",locno="3",frame=@{
> +func="foo",args=[],file="hello.c",fullname="/home/foo/bar/hello.c",
> +line="13",arch="i386:x86_64"@}
> +(gdb)
> +@end smallexample
>  
> 
>  @subheading The @code{-exec-finish} Command
>  @findex -exec-finish
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 02c98b50c8c..e5ad062a914 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -8494,7 +8494,21 @@ print_stop_location (const target_waitstatus &ws)
>       LOCATION: Print only location
>       SRC_AND_LOC: Print location and source line.  */
>    if (do_frame_printing)
> -    print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    {
> +      if (tp->control.stop_bpstat != nullptr)
> +	{
> +	  const struct breakpoint *b = tp->control.stop_bpstat->breakpoint_at;
> +
> +	  if (b != nullptr)
> +	    {
> +	      int locno = bpstat_locno (tp->control.stop_bpstat);
> +	      set_internalvar_integer (lookup_internalvar ("bkptno"), b->number);
> +	      set_internalvar_integer (lookup_internalvar ("locno"),
> +				       (locno > 0 ? locno : 1));
> +	    }
> +	}
> +      print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    }
>  }
>  
> 
>  /* See infrun.h.  */
> diff --git a/gdb/testsuite/gdb.ada/bp_inlined_func.exp b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> index 076e8c2425f..3f94c163819 100644
> --- a/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> +++ b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> @@ -42,7 +42,7 @@ gdb_test "break read_small" \
>  for {set i 0} {$i < 4} {incr i} {
>      with_test_prefix "iteration $i" {
>  	gdb_test "continue" \
> -	    "Breakpoint $decimal, b\\.read_small \\(\\).*" \
> +	    "Breakpoint $bkptno_num_re, b\\.read_small \\(\\).*" \
>  	    "stopped in read_small"
>      }
>  }
> diff --git a/gdb/testsuite/gdb.ada/operator_bp.exp b/gdb/testsuite/gdb.ada/operator_bp.exp
> index 655e7af479f..e3928419ed6 100644
> --- a/gdb/testsuite/gdb.ada/operator_bp.exp
> +++ b/gdb/testsuite/gdb.ada/operator_bp.exp
> @@ -56,7 +56,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to \"$op\""
>  }
>  
> 
> @@ -86,7 +86,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to ops.\"$op\""
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> index b540df973a3..742315178e3 100644
> --- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> +++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> @@ -140,11 +140,11 @@ with_test_prefix "scenario 1" {
>      gdb_run_cmd
>  
> 
>      # Check our conditional breakpoints.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> @@ -208,11 +208,11 @@ with_test_prefix "scenario 2" {
>      gdb_run_cmd
>  
> 
>      # Check that we hit enabled locations only.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> diff --git a/gdb/testsuite/gdb.base/ctxobj.exp b/gdb/testsuite/gdb.base/ctxobj.exp
> index 9c010f54d79..0b589a7d6e6 100644
> --- a/gdb/testsuite/gdb.base/ctxobj.exp
> +++ b/gdb/testsuite/gdb.base/ctxobj.exp
> @@ -67,9 +67,16 @@ gdb_test "break ctxobj-f.c:$bp_location" \
>           "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
>           "break in get_version functions"
>  
> 
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_1 \\(\\).*" \
> -         "continue to get_version_1"
> +global expect_out
> +set test "continue to get_version_1"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_1 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  # Try printing "this_version_num".  There are two global variables
>  # with that name, and some systems such as GNU/Linux merge them
> @@ -100,10 +107,15 @@ gdb_test "print this_version_num == v" \
>          "print libctxobj1's this_version_num from symtab"
>  
> 
>  # Do the same, but from get_version_2.
> -
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_2 \\(\\).*" \
> -         "continue to get_version_2"
> +set test "continue to get_version_2"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_2 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  gdb_test "print this_version_num == v" \
>           " = 1" \
> diff --git a/gdb/testsuite/gdb.base/ena-dis-br.exp b/gdb/testsuite/gdb.base/ena-dis-br.exp
> index 24925cf7185..04b3f134b44 100644
> --- a/gdb/testsuite/gdb.base/ena-dis-br.exp
> +++ b/gdb/testsuite/gdb.base/ena-dis-br.exp
> @@ -67,14 +67,21 @@ gdb_test "info break $bp" \
>  # See the comments in condbreak.exp for "run until breakpoint at
>  # marker1" for an explanation of the xfail below.
>  set test "continue to break marker1"
> +set bpno 0
>  gdb_test_multiple "continue" "$test" {
> -    -re "Breakpoint \[0-9\]*, marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	pass "$test"
>      }
> -    -re "Breakpoint \[0-9\]*, $hex in marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), $hex in marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	xfail "$test"
>      }
>  }
> +# Verify the $bkptno convenience variable is equal to the hit bpno.
> +gdb_test "print \$bkptno" " = $bpno" "$test \$bkptno is $bpno"
> +# Verify the $locno is 1, as there is only one code location.
> +gdb_test "print \$locno" " = 1" "$test \$locno is 1"
>  
> 
>  gdb_test_no_output "delete $bp" "delete break marker1"
>  
> 
> @@ -359,7 +366,8 @@ with_test_prefix "4th breakpoint" {
>  }
>  
> 
>  # Perform tests for disable/enable commands on multiple
> -# locations and breakpoints.
> +# code locations and breakpoints.  If a breakpoint has only one code location,
> +# enable/disable num  and enable/disable num.1 should be equivalent.
>  #
>  # WHAT - the command to test (disable/enable).
>  #
> @@ -372,7 +380,7 @@ proc test_ena_dis_br { what } {
>      global b3
>      global b4
>      global gdb_prompt
> -    
> +
>      # OPPOS    - the command opposite to WHAT.
>      # WHAT_RES - whether breakpoints are expected to end
>      #            up enabled or disabled.
> @@ -395,13 +403,13 @@ proc test_ena_dis_br { what } {
>  	set p2 "pass"
>      }
>  
> 
> -    # Now enable(disable) $b.1 $b2.1.
> +    # Now enable(disable) $b1.1 $b2.1.
>      gdb_test_no_output "$what $b1.1 $b2.1" "$what \$b1.1 \$b2.1"
>      set test1 "${what}d \$b1.1 and \$b2.1"
>  
> 
>      # Now $b1.1 and $b2.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -       -re "(${b1}.1)(\[^\n\r\]*)( n.*)(${b2}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +       -re "(${b1})(\[^\n\r\]*)( n.*)(${b2})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> @@ -420,19 +428,16 @@ proc test_ena_dis_br { what } {
>         "${what}d \$b1"
>  
> 
>      gdb_test_no_output "$oppos $b3" "$oppos \$b3"
> +    # Now $b4 $b3 should be enabled(disabled)
> +    set test1 "${what}d \$b4 and \$b3"
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $oppos_res.*).*(${b4})(\[^\n\r\]*)( $oppos_res.*)" "$test1"
> +
>      gdb_test_no_output "$what $b4 $b3.1" "$what \$b4 \$b3.1"
> -    set test1 "${what}d \$b4 and \$b3.1,remain ${oppos}d \$b3"
> +    set test1 "${what}d \$b4 and \$b3.1, changing \$b3"
> +
> +    # Now $b4 $b3 should be enabled(disabled)
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $what_res.*).*(${b4})(\[^\n\r\]*)( $what_res.*)" "$test1"
>  
> 
> -    # Now $b4 $b3.1 should be enabled(disabled) and
> -    # $b3 should remain disabled(enabled).
> -    gdb_test_multiple "info break" "$test1" {
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b3}.1)(\[^\n\r\]*)( n.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p1 "$test1"
> -       }
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p2 "$test1"
> -       }
> -    }
>  
> 
>      # Now enable(disable) '$b4.1 fooobaar'.  This should error on
>      # fooobaar.
> @@ -443,7 +448,7 @@ proc test_ena_dis_br { what } {
>  
> 
>      # $b4.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -        -re "(${b4}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +        -re "(${b4})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.base/foll-exec-mode.exp b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> index 918f3e4fd5f..cb6d975a767 100644
> --- a/gdb/testsuite/gdb.base/foll-exec-mode.exp
> +++ b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> @@ -99,7 +99,7 @@ proc do_catch_exec_test { } {
>  # before re-running.
>  
> 
>  proc do_follow_exec_mode_tests { mode cmd infswitch } {
> -    global binfile srcfile srcfile2 testfile testfile2
> +    global binfile srcfile srcfile2 testfile testfile2 bkptno_numopt_re
>      global gdb_prompt
>  
> 
>      with_test_prefix "$mode,$cmd,$infswitch" {
> @@ -125,7 +125,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  	# Set up the output we expect to see after we execute past the exec.
>  	#
>  	set execd_line [gdb_get_line_number "after-exec" $srcfile2]
> -	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint .,.*${srcfile2}:${execd_line}.*$gdb_prompt $"
> +	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint ${bkptno_numopt_re},.*${srcfile2}:${execd_line}.*$gdb_prompt $"
>  
> 
>  	# Set a breakpoint after the exec call if we aren't single-stepping
>  	# past it.
> @@ -189,7 +189,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  		send_gdb "y\n"
>  		exp_continue
>  	    }
> -	    -re "Starting program: .*$expected_inf.*Breakpoint .,.*\r\n$gdb_prompt $" {
> +	    -re "Starting program: .*$expected_inf.*Breakpoint $bkptno_numopt_re,.*\r\n$gdb_prompt $" {
>  		pass $test
>  	    }
>  	}
> diff --git a/gdb/testsuite/gdb.base/pie-fork.exp b/gdb/testsuite/gdb.base/pie-fork.exp
> index efc357d39a2..19e9d3a5537 100644
> --- a/gdb/testsuite/gdb.base/pie-fork.exp
> +++ b/gdb/testsuite/gdb.base/pie-fork.exp
> @@ -54,10 +54,10 @@ proc_with_prefix test_detach_on_fork_follow_child {} {
>  proc_with_prefix test_no_detach_on_fork {} {
>      setup_test "off"
>  
> 
> -    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2.1, break_here.*" \
>  	     "continue from thread 1.1"
>      gdb_test "thread 2.1"
> -    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2.2, break_here.*" \
>  	     "continue from thread 2.1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/step-over-exit.exp b/gdb/testsuite/gdb.base/step-over-exit.exp
> index f8bd99980fe..575319c564c 100644
> --- a/gdb/testsuite/gdb.base/step-over-exit.exp
> +++ b/gdb/testsuite/gdb.base/step-over-exit.exp
> @@ -91,7 +91,7 @@ delete_breakpoints
>  
> 
>  gdb_test "break marker"
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_num_re, .*" \
>      "continue to marker, first time"
>  
> 
>  # Step 2, create a breakpoint which evaluates false, and force it
> @@ -120,5 +120,5 @@ gdb_test "inferior 1" ".*Switching to inferior 1.*" \
>  # Switch back to the parent process, continue to the marker to
>  # test GDBserver's state is still correct.
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_numopt_re, .*" \
>      "continue to marker, second time"
> diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
> index 47a2a5dcb7c..fa098602c31 100644
> --- a/gdb/testsuite/gdb.cp/mb-inline.exp
> +++ b/gdb/testsuite/gdb.cp/mb-inline.exp
> @@ -46,7 +46,7 @@ gdb_test "info break" \
>      "\[\r\n\]1\.1.* y .* at .*$hdrfile:$bp_location.*\[\r\n\]1\.2.* y .* at .*$hdrfile:$bp_location.*"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo \\(i=1\\).*" \
> @@ -59,7 +59,7 @@ gdb_test "continue" \
>  gdb_test_no_output "disable 1.2" "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
>  
> 
>  gdb_test_multiple "info break" "disabled breakpoint 1.2" {
>      -re "1\.2.* n .* at .*$hdrfile:$bp_location.*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
> index 6c988e7335e..0c0d46fcb7a 100644
> --- a/gdb/testsuite/gdb.cp/mb-templates.exp
> +++ b/gdb/testsuite/gdb.cp/mb-templates.exp
> @@ -42,7 +42,7 @@ gdb_run_cmd
>  
> 
>  set test "initial condition: run to breakpoint"
>  gdb_test_multiple "" $test {
> -    -re "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
> +    -re "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
>  	pass $test
>  	break
>      }
> @@ -67,7 +67,7 @@ gdb_test_no_output {condition $bpnum i==1} \
>      "separate condition: set condition"
>      
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo<double> \\(i=1\\).*" \
> @@ -79,7 +79,7 @@ gdb_test "continue" \
>  gdb_test_no_output {disable $bpnum.1} "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
>  
> 
>  # Try disabling entire breakpoint
>  gdb_test_no_output {enable $bpnum.1} "disabling location: enable"
> diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
> index 06adf82ecbb..0ed9eae055b 100644
> --- a/gdb/testsuite/gdb.cp/ovldbreak.exp
> +++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
> @@ -380,7 +380,7 @@ gdb_test "info break" $bptable "breakpoint info (after setting on all)"
>  
> 
>  # Run through each breakpoint.
>  proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
> -    global gdb_prompt hex decimal srcfile
> +    global gdb_prompt hex decimal srcfile bkptno_num_re
>  
> 
>      if {$argument == ""} {
>          set actuals ""
> @@ -398,11 +398,11 @@ proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
>      }
>  
> 
>      gdb_test_multiple "continue" "continue to bp overloaded : $argtype" {
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              pass "continue to bp overloaded : $argtype"
>          }
>  
> 
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              if $might_kfail {
>                  kfail "c++/8130" "continue to bp overloaded : $argtype"
>              } else {
> diff --git a/gdb/testsuite/gdb.gdb/python-helper.exp b/gdb/testsuite/gdb.gdb/python-helper.exp
> index 6db8bf0df50..30eb6038f3a 100644
> --- a/gdb/testsuite/gdb.gdb/python-helper.exp
> +++ b/gdb/testsuite/gdb.gdb/python-helper.exp
> @@ -49,7 +49,7 @@ gdb_exit
>  # The main test.  This is called by the self-test framework once GDB
>  # has been started on a copy of itself.
>  proc test_python_helper {} {
> -    global py_helper_script decimal hex gdb_prompt
> +    global py_helper_script decimal hex gdb_prompt bkptno_numopt_re
>      global inferior_spawn_id
>  
> 
>      # Source the python helper script.  This script registers the
> @@ -233,7 +233,7 @@ proc test_python_helper {} {
>      # GDB stopping at the value_print breakpoint again.
>      send_inferior "ptype global_c\n"
>      gdb_test_multiple "" "hit breakpoint in outer gdb again" {
> -	-re "Breakpoint $decimal, c_print_type .*\\(outer-gdb\\) $" {
> +	-re "Breakpoint $bkptno_numopt_re, c_print_type .*\\(outer-gdb\\) $" {
>  	    pass $gdb_test_name
>  	}
>      }
> diff --git a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> index 19ccbe85e04..c080955049c 100644
> --- a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> +++ b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> @@ -69,7 +69,7 @@ if { $use_second_inferior } {
>  	"\\^running.*" \
>  	"run inferior 2"
>  
> 
> -    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\""} \
> +    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\"" "locno=\"[0-9]+\""} \
>  	"inferior i2 stops at all_threads_started"
>  
> 
>      mi_send_resuming_command "exec-continue --thread-group i2" \
> diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> index d78c96ddef1..9eec083068b 100644
> --- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> +++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> @@ -307,8 +307,13 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  	    # Consume MI event output.
>  	    with_spawn_id $mi_spawn_id {
> -		mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> -		    "$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		if { $inf == 1 } {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		} else {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} "stop at breakpoint in main"
> +		}
>  	    }
>  
> 
>  	    if { $mode == "all-stop" } {
> @@ -330,9 +335,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		    # Consume MI output.
>  		    with_spawn_id $mi_spawn_id {
> -			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			    "thread $inf.$thread stops MI"
> +			if { $inf == 1} {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +				"thread $inf.$thread stops MI"
> +			} else {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +				"thread $inf.$thread stops MI"
> +			}
>  		    }
>  		}
>  
> 
> @@ -359,9 +370,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		# Consume MI output.
>  		with_spawn_id $mi_spawn_id {
> -		    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			"thread $inf.2 stops MI"
> +		    if { $inf == 1} {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +			    "thread $inf.2 stops MI"
> +		    } else {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +			    "thread $inf.2 stops MI"
> +		    }
>  		}
>  	    }
>  	}
> @@ -434,7 +451,7 @@ proc_with_prefix test_setup { mode } {
>  
> 
>  	with_spawn_id $mi_spawn_id {
>  	    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" "$decimal" \
> -		{"" "disp=\"del\""} "main stop"
> +		{"" "disp=\"del\"" "locno=\"[0-9]+\""} "main stop"
>  	}
>  
> 
>  	# Consume CLI output.
> diff --git a/gdb/testsuite/gdb.multi/multi-arch-exec.exp b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> index a1496fb5571..dfdb746c65e 100644
> --- a/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> +++ b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> @@ -148,6 +148,7 @@ proc build_executables { first_arch } {
>  }
>  
> 
>  proc do_test { first_arch mode selected_thread } {
> +        global bkptno_numopt_re
>  	set from_exec "$first_arch-multi-arch-exec"
>  
> 
>  	clean_restart ${from_exec}
> @@ -169,7 +170,7 @@ proc do_test { first_arch mode selected_thread } {
>  
> 
>  	# Test that GDB updates the target description / arch successfuly
>  	# after the exec.
> -	gdb_test "continue" "Breakpoint 2, main.*" "continue across exec that changes architecture"
> +	gdb_test "continue" "Breakpoint $bkptno_numopt_re, main.*" "continue across exec that changes architecture"
>  }
>  
> 
>  # Test both arch1=>arch2 and arch2=>arch1.
> diff --git a/gdb/testsuite/gdb.multi/run-only-second-inf.exp b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> index fec2575f904..b94689d0bfa 100644
> --- a/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> +++ b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> @@ -46,5 +46,5 @@ gdb_load $binfile
>  if {[gdb_start_cmd] < 0} {
>      fail "start the second inf"
>  } else {
> -    gdb_test "" ".*reakpoint ., main .*${srcfile}.*" "start the second inf"
> +    gdb_test "" ".*reakpoint $bkptno_numopt_re, main .*${srcfile}.*" "start the second inf"
>  }
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> index cbccba19d12..3c079facced 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> @@ -27,7 +27,7 @@ if {[build_executable "failed to build" $testfile $srcfile {debug}]} {
>  # child.  Can be either "kill", "detach", or "exit" (to continue it to
>  # normal exit).
>  proc do_test {dispose} {
> -    global binfile
> +    global binfile bkptno_numopt_re
>  
> 
>      clean_restart $binfile
>  
> 
> @@ -77,7 +77,7 @@ proc do_test {dispose} {
>      #  Command aborted.
>      #  (gdb)
>      #
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker .*" \
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker .*" \
>  	"continue in inferior 1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi.exp b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> index e4329dca6c2..0fc1bee762f 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> @@ -84,11 +84,11 @@ if [skip_hw_watchpoint_multi_tests] {
>  	"Hardware access \\(read/write\\) watchpoint \[0-9\]+: c\r\n\r\nOld value = 0\r\nNew value = 3\r\n.*" \
>  	"catch c on inferior 2"
>  
> 
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 2"
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 2"
>  
> 
>      gdb_test "inferior 1" "witching to inferior 1 .*" "switch back to inferior 1 again"
>  
> 
>      gdb_test "continue" "Hardware access \\(read/write\\) watchpoint \[0-9\]+: b\r\n\r\nOld value = 0\r\nNew value = 2\r\n.*" "catch b on inferior 1"
>  }
>  
> 
> -gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 1"
> +gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 1"
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 402450152ac..5e4c793598e 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -227,6 +227,14 @@ set inferior_exited_re "(?:\\\[Inferior \[0-9\]+ \\(\[^\n\r\]*\\) exited)"
>  # E.g., $1, $2, etc.
>  set valnum_re "\\\$$decimal"
>  
> 
> +# A regular expression that matches a breakpoint hit with a breakpoint
> +# having several code locations.
> +set bkptno_num_re "$decimal\\.$decimal"
> +
> +# A regular expression that matches a breakpoint hit
> +# with one or several code locations.
> +set bkptno_numopt_re "($decimal\\.$decimal|$decimal)"
> +
>  ### Only procedures should come after this point.
>  
> 
>  #
> @@ -662,6 +670,7 @@ proc gdb_breakpoint { linespec args } {
>  
> 
>  proc runto { linespec args } {
>      global gdb_prompt
> +    global bkptno_numopt_re
>      global decimal
>  
> 
>      delete_breakpoints
> @@ -699,7 +708,7 @@ proc runto { linespec args } {
>  	    }
>  	    return 1
>  	}
> -	-re "Breakpoint \[0-9\]*, \[0-9xa-f\]* in .*$gdb_prompt $" { 
> +	-re "Breakpoint $bkptno_numopt_re, \[0-9xa-f\]* in .*$gdb_prompt $" {
>  	    if { $print_pass } {
>  		pass $test_name
>  	    }
> diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
> index e578a7e6f9b..ea66fdcabf8 100644
> --- a/gdb/testsuite/lib/mi-support.exp
> +++ b/gdb/testsuite/lib/mi-support.exp
> @@ -1195,11 +1195,11 @@ proc mi_detect_async {} {
>  # filename of a file without debug info.  ARGS should not include [] the
>  # list of argument is enclosed in, and other regular expressions should
>  # not include quotes.
> -# If EXTRA is a list of one element, it's the regular expression
> +# EXTRA can be a list of one, two or three elements.
> +# The first element is the regular expression
>  # for output expected right after *stopped, and before GDB prompt.
> -# If EXTRA is a list of two elements, the first element is for
> -# output right after *stopped, and the second element is output
> -# right after reason field.  The regex after reason should not include
> +# The third element is the regulation expression for the locno
> +# right after bkptno field.  The locno regex should not include
>  # the comma separating it from the following fields.
>  #
>  # When we fail to match output at all, -1 is returned.  If FILE does
> @@ -1224,7 +1224,14 @@ proc mi_expect_stop { reason func args file line extra test } {
>  
> 
>      set after_stopped ""
>      set after_reason ""
> -    if { [llength $extra] == 2 } {
> +    set locno ""
> +    if { [llength $extra] == 3 } {
> +	set after_stopped [lindex $extra 0]
> +	set after_reason [lindex $extra 1]
> +	set after_reason "${after_reason},"
> +	set locno [lindex $extra 2]
> +	set locno "${locno},"
> +    } elseif { [llength $extra] == 2 } {
>  	set after_stopped [lindex $extra 0]
>  	set after_reason [lindex $extra 1]
>  	set after_reason "${after_reason},"
> @@ -1298,10 +1305,12 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set ebn ""
>      if { $reason == "breakpoint-hit" } {
>  	set bn {bkptno="[0-9]+",}
> +	set bn "${bn}${locno}"
>      } elseif { $reason == "solib-event" } {
>  	set bn ".*"
>      } elseif { $reason == "exception-caught" } {
>  	set ebn {bkptno="[0-9]+",}
> +	set ebn "${ebn}${locno}"
>  	set bn ".*"
>  	set reason "breakpoint-hit"
>      }
> @@ -1315,6 +1324,7 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set a $after_reason
>  
> 
>      verbose -log "mi_expect_stop: expecting: \\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
> +
>      gdb_expect {
>  	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
>  	    pass "$test"



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-06-06  9:45 [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno Philippe Waroquiers
                   ` (7 preceding siblings ...)
  2022-08-14 14:08 ` Philippe Waroquiers
@ 2022-08-21 12:05 ` Philippe Waroquiers
  2022-08-27 14:45 ` Philippe Waroquiers
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Philippe Waroquiers @ 2022-08-21 12:05 UTC (permalink / raw)
  To: gdb-patches


Ping ^ 8
(Eli reviewed the doc, Keith did a first review)

Thanks
Philippe


On Mon, 2022-06-06 at 11:45 +0200, Philippe Waroquiers wrote:
> Before this patch, when a breakpoint that has multiple locations is reached,
> GDB printed:
>   Thread 1 "zeoes" hit Breakpoint 1, some_func () at somefunc1.c:5
> 
> This patch changes the message so that bkpt_print_id prints the precise
> encountered breakpoint:
>   Thread 1 "zeoes" hit Breakpoint 1.2, some_func () at somefunc1.c:5
> 
> In mi mode, bkpt_print_id also (optionally) prints a new table field "locno":
>   locno is printed when the breakpoint has more than one location.
> Note that according to the GDB user manual node 'GDB/MI Development and Front
> Ends', it is ok to add new fields without changing the MI version.
> 
> Also, when a breakpoint is reached, the convenience variables
> $bkptno and $locno are set to the encountered breakpoint number
> and location number.
> 
> $bkptno and $locno can a.o. be used in the command list of a breakpoint,
> to disable the specific encountered breakpoint, e.g.
>    disable $bkptno.$locno
> 
> In case the breakpoint has only one location, $locno is still set to
> the value 1, so as to allow a command such as:
>   disable $bkptno.$locno
> even when the breakpoint has only one location.
> 
> This also fixes a strange behaviour: when a breakpoint X has only
> one location,
>   enable|disable X.1
> is accepted but transforms the breakpoint in a multiple locations
> breakpoint having only one location.
> 
> The changes in RFA v3 handle the additional comments of Eli:
>  GDB/NEW:
>   - Use max 80-column
>   - Use 'code location' instead of 'location'.
>   - Fix typo $bkpno
>   - Ensure that disable $bkptno and disable $bkptno.$locno have
>     each their explanation inthe example
>   - Reworded the 'breakpoint-hit' paragraph.
>  gdb.texinfo:
>   - Use 'code location' instead of 'location'.
>   - Add a note to clarify the distinction between $bkptno and $bpnum.
>   - Use @kbd instead of examples with only one command.
> 
> Compared to RFA v1, the changes in v2 handle the comments given by
> Keith Seitz and Eli Zaretskii:
>   - Use %s for the result of paddress
>   - Use bkptno_numopt_re instead of 2 different -re cases
>   - use C@t{++}
>   - Add index entries for $bkptno and $locno
>   - Added an example for "locno" in the mi interface
>   - Added examples in the Break command manual.
> ---
>  gdb/NEWS                                      | 21 +++++
>  gdb/ada-lang.c                                |  2 +-
>  gdb/break-catch-syscall.c                     |  2 +-
>  gdb/break-catch-throw.c                       |  2 +-
>  gdb/breakpoint.c                              | 93 +++++++++++++++----
>  gdb/breakpoint.h                              | 14 +++
>  gdb/doc/gdb.texinfo                           | 83 ++++++++++++++++-
>  gdb/infrun.c                                  | 16 +++-
>  gdb/testsuite/gdb.ada/bp_inlined_func.exp     |  2 +-
>  gdb/testsuite/gdb.ada/operator_bp.exp         |  4 +-
>  .../gdb.base/condbreak-multi-context.exp      |  8 +-
>  gdb/testsuite/gdb.base/ctxobj.exp             | 26 ++++--
>  gdb/testsuite/gdb.base/ena-dis-br.exp         | 41 ++++----
>  gdb/testsuite/gdb.base/foll-exec-mode.exp     |  6 +-
>  gdb/testsuite/gdb.base/pie-fork.exp           |  4 +-
>  gdb/testsuite/gdb.base/step-over-exit.exp     |  4 +-
>  gdb/testsuite/gdb.cp/mb-inline.exp            |  4 +-
>  gdb/testsuite/gdb.cp/mb-templates.exp         |  6 +-
>  gdb/testsuite/gdb.cp/ovldbreak.exp            |  6 +-
>  gdb/testsuite/gdb.gdb/python-helper.exp       |  4 +-
>  .../gdb.mi/interrupt-thread-group.exp         |  2 +-
>  .../gdb.mi/user-selected-context-sync.exp     | 35 +++++--
>  gdb/testsuite/gdb.multi/multi-arch-exec.exp   |  3 +-
>  .../gdb.multi/run-only-second-inf.exp         |  2 +-
>  .../gdb.multi/watchpoint-multi-exit.exp       |  4 +-
>  gdb/testsuite/gdb.multi/watchpoint-multi.exp  |  4 +-
>  gdb/testsuite/lib/gdb.exp                     | 11 ++-
>  gdb/testsuite/lib/mi-support.exp              | 20 +++-
>  28 files changed, 335 insertions(+), 94 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 960f90b4387..a5602deee2b 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -34,6 +34,21 @@
>       whitespace from each line before using the string as the help
>       output.
>  
> 
> +* When a breakpoint with multiple code locations is hit, GDB now prints
> +  the code location using the syntax <breakpoint_number>.<location_number>
> +  such as in:
> +     Thread 1 "zeoes" hit Breakpoint 2.3, some_func () at zeoes.c:8
> +
> +* When a breakpoint is hit, GDB now sets the convenience variables $bkptno and
> +  $locno to the hit breakpoint number and code location number.
> +  This allows to disable the last hit breakpoint using
> +     (gdb) disable $bkptno
> +   or disable only the specific breakpoint code location using
> +     (gdb) disable $bkptno.$locno
> +  These commands can be used inside the command list of a breakpoint to
> +  automatically disable the just encountered breakpoint (or the just
> +  encountered specific breakpoint code location).
> +
>  * New commands
>  
> 
>  maintenance set ignore-prologue-end-flag on|off
> @@ -50,6 +65,12 @@ maintenance info line-table
>    entry corresponds to an address where a breakpoint should be placed
>    to be at the first instruction past a function's prologue.
>  
> 
> +* MI changes
> +
> + ** The async record stating the stopped reason 'breakpoint-hit' now
> +    contains an optional field locno giving the code location number
> +    when the breakpoint has multiple code locations.
> +
>  * Python API
>  
> 
>    ** New function gdb.format_address(ADDRESS, PROGSPACE, ARCHITECTURE),
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 6ab01fd27d4..bbae76f39ac 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -12348,7 +12348,7 @@ ada_catchpoint::print_it (const bpstat *bs) const
>  
> 
>    uiout->text (disposition == disp_del
>  	       ? "\nTemporary catchpoint " : "\nCatchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    /* ada_exception_name_addr relies on the selected frame being the
> diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
> index 06d48466de7..82229de33f7 100644
> --- a/gdb/break-catch-syscall.c
> +++ b/gdb/break-catch-syscall.c
> @@ -218,7 +218,7 @@ syscall_catchpoint::print_it (const bpstat *bs) const
>  						: EXEC_ASYNC_SYSCALL_RETURN));
>        uiout->field_string ("disp", bpdisp_text (b->disposition));
>      }
> -  uiout->field_signed ("bkptno", b->number);
> +  print_num_locno (bs, uiout);
>  
> 
>    if (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY)
>      uiout->text (" (call to syscall ");
> diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
> index 66cf80be1c5..5b6f5d9eca1 100644
> --- a/gdb/break-catch-throw.c
> +++ b/gdb/break-catch-throw.c
> @@ -257,7 +257,7 @@ exception_catchpoint::print_it (const bpstat *bs) const
>    bp_temp = disposition == disp_del;
>    uiout->text (bp_temp ? "Temporary catchpoint "
>  		       : "Catchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text ((kind == EX_EVENT_THROW ? " (exception thrown), "
>  		: (kind == EX_EVENT_CATCH ? " (exception caught), "
>  		   : " (exception rethrown), ")));
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index ed932a19ed7..c89c800f32f 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -820,6 +820,19 @@ get_breakpoint (int num)
>    return nullptr;
>  }
>  
> 
> +/* Return TRUE if NUM refer to an existing breakpoint that has
> +   multiple code locations.  */
> +
> +static bool
> +has_multiple_locations (int num)
> +{
> +  for (breakpoint *b : all_breakpoints ())
> +    if (b->number == num)
> +      return b->loc != nullptr && b->loc->next != nullptr;
> +
> +  return false;
> +}
> +
>  \f
>  
> 
>  /* Mark locations as "conditions have changed" in case the target supports
> @@ -4451,15 +4464,7 @@ bpstat_explains_signal (bpstat *bsp, enum gdb_signal sig)
>    return false;
>  }
>  
> 
> -/* Put in *NUM the breakpoint number of the first breakpoint we are
> -   stopped at.  *BSP upon return is a bpstat which points to the
> -   remaining breakpoints stopped at (but which is not guaranteed to be
> -   good for anything but further calls to bpstat_num).
> -
> -   Return 0 if passed a bpstat which does not indicate any breakpoints.
> -   Return -1 if stopped at a breakpoint that has been deleted since
> -   we set it.
> -   Return 1 otherwise.  */
> +/* See breakpoint.h.  */
>  
> 
>  int
>  bpstat_num (bpstat **bsp, int *num)
> @@ -4481,6 +4486,57 @@ bpstat_num (bpstat **bsp, int *num)
>    return 1;
>  }
>  
> 
> +/* See breakpoint.h  */
> +
> +int
> +bpstat_locno (const bpstat *bs)
> +{
> +  const struct breakpoint *b = bs->breakpoint_at;
> +  const struct bp_location *bl = bs->bp_location_at.get ();
> +
> +  int locno = 0;
> +
> +  if (b != nullptr && b->loc->next != nullptr)
> +    {
> +      const bp_location *bl_i;
> +
> +      for (bl_i = b->loc;
> +	   bl_i != bl && bl_i->next != nullptr;
> +	   bl_i = bl_i->next)
> +	locno++;
> +
> +      if (bl_i == bl)
> +	locno++;
> +      else
> +	{
> +	  warning (_("location number not found for breakpoint %d address %s."),
> +		   b->number, paddress (bl->gdbarch, bl->address));
> +	  locno = 0;
> +	}
> +    }
> +
> +  return locno;
> +}
> +
> +/* See breakpoint.h.  */
> +
> +void
> +print_num_locno (const bpstat *bs, struct ui_out *uiout)
> +{
> +  struct breakpoint *b = bs->breakpoint_at;
> +
> +  if (b == nullptr)
> +    uiout->text (_("deleted breakpoint"));
> +  else
> +    {
> +      uiout->field_signed ("bkptno", b->number);
> +
> +      int locno = bpstat_locno (bs);
> +      if (locno != 0)
> +	uiout->message (".%pF", signed_field ("locno", locno));
> +    }
> +}
> +
>  /* See breakpoint.h.  */
>  
> 
>  void
> @@ -9176,7 +9232,7 @@ ranged_breakpoint::print_it (const bpstat *bs) const
>  		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
> @@ -11610,12 +11666,13 @@ ordinary_breakpoint::print_it (const bpstat *bs) const
>  			   async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> +
>    if (bp_temp)
> -    uiout->message ("Temporary breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Temporary breakpoint ");
>    else
> -    uiout->message ("Breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Breakpoint ");
> +  print_num_locno (bs, uiout);
> +  uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
>  }
> @@ -13220,9 +13277,13 @@ enable_disable_command (const char *args, int from_tty, bool enable)
>  	  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)
> +	      && (bp_loc_range.first == 0
> +		  || (bp_loc_range.first == 1
> +		      && bp_num_range.first == bp_num_range.second
> +		      && !has_multiple_locations (bp_num_range.first))))
>  	    {
> -	      /* Handle breakpoint ids with formats 'x' or 'x-z'.  */
> +	      /* Handle breakpoint ids with formats 'x' or 'x-z'
> +		 or 'y.1' where y has only one code location.  */
>  	      map_breakpoint_number_range (bp_num_range,
>  					   enable
>  					   ? enable_breakpoint
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 566f1285e46..96d61ef5427 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -1231,6 +1231,20 @@ extern enum print_stop_action bpstat_print (bpstat *, int);
>     Return 1 otherwise.  */
>  extern int bpstat_num (bpstat **, int *);
>  
> 
> +/* If BS indicates a breakpoint and this breakpoint has several code locations,
> +   return the location number of BS, otherwise return 0.  */
> +
> +extern int bpstat_locno (const bpstat *bs);
> +
> +/* Print BS breakpoint number optionally followed by a . and breakpoint locno.
> +
> +   For a breakpoint with only one code location, outputs the signed field
> +   "bkptno" breakpoint number of BS (as returned by bpstat_num).
> +   If BS has several code locations, outputs a '.' character followed by
> +   the signed field "locno" (as returned by bpstat_locno).  */
> +
> +extern void print_num_locno (const bpstat *bs, struct ui_out *);
> +
>  /* Perform actions associated with the stopped inferior.  Actually, we
>     just use this for breakpoint commands.  Perhaps other actions will
>     go here later, but this is executed at a late time (from the
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 434add3a663..391b81f8863 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -4338,9 +4338,65 @@ are operated on.
>  @cindex latest breakpoint
>  Breakpoints are set with the @code{break} command (abbreviated
>  @code{b}).  The debugger convenience variable @samp{$bpnum} records the
> -number of the breakpoint you've set most recently; see @ref{Convenience
> -Vars,, Convenience Variables}, for a discussion of what you can do with
> -convenience variables.
> +number of the breakpoint you've set most recently:
> +@smallexample
> +(gdb) b main
> +Breakpoint 1 at 0x11c6: file zeoes.c, line 24.
> +(gdb) p $bpnum
> +$1 = 1
> +@end smallexample
> +
> +A breakpoint may be mapped to multiple code locations for example with
> +inlined functions, Ada generics, C@t{++} templates or overloaded function names.
> +@value{GDBN} then indicates the number of code locations in the breakpoint
> +command output:
> +@smallexample
> +(gdb) b some_func
> +Breakpoint 2 at 0x1179: some_func. (3 locations)
> +(gdb) p $bpnum
> +$2 = 2
> +(gdb)
> +@end smallexample
> +
> +@vindex $bkptno@r{, convenience variable}
> +@vindex $locno@r{, convenience variable}
> +When your program stops on a breakpoint, the convenience variables
> +@samp{$bkptno} and @samp{$locno} are respectively set to the number of
> +the encountered breakpoint and the number of the breakpoint's code location:
> +@smallexample
> +Thread 1 "zeoes" hit Breakpoint 2.1, some_func () at zeoes.c:8
> +8	  printf("some func\n");
> +(gdb) p $bkptno
> +$5 = 2
> +(gdb) p $locno
> +$6 = 1
> +(gdb)
> +@end smallexample
> +
> +Note that @samp{$bkptno} and @samp{$bpnum} are not equivalent:
> +@samp{$bkptno} is set to the breakpoint number @b{last hit}, while
> +@samp{$bpnum} is set to the breakpoint number @b{last set}.
> +
> +
> +If the encountered breakpoint has only one code location, @samp{$locno} is set
> +to 1:
> +@smallexample
> +Breakpoint 1, main (argc=1, argv=0x7fffffffe018) at zeoes.c:24
> +24	  if (argc > 1)
> +(gdb) p $bkptno
> +$3 = 1
> +(gdb) p $locno
> +$4 = 1
> +(gdb)
> +@end smallexample
> +
> +The @samp{$bkptno} and @samp{$locno} variables can typically be used
> +in a breakpoint command list.
> +(@pxref{Break Commands, ,Breakpoint Command Lists}). For example, as
> +part of the breakpoint command list, you can disable completely the
> +encountered breakpoint using @samp{disable $bkptno} or disable the
> +specific encountered breakpoint location using @samp{disable
> +$bkptno.$locno}.
>  
> 
>  @table @code
>  @item break @var{locspec}
> @@ -5739,6 +5795,13 @@ Expressions}).
>  Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
>  disabled within a @var{command-list}.
>  
> 
> +Inside a command list, you can use the command
> +@kbd{disable $bkptno} to disable the encountered breakpoint.
> +
> +If your breakpoint has several code locations, the command
> +@kbd{disable $bkptno.$locno} will disable the specific breakpoint code
> +location encountered.
> +
>  You can use breakpoint commands to start your program up again.  Simply
>  use the @code{continue} command, or @code{step}, or any other command
>  that resumes execution.
> @@ -32570,6 +32633,20 @@ line="13",arch="i386:x86_64"@}
>  (gdb)
>  @end smallexample
>  
> 
> +For a @samp{breakpoint-hit} stopped reason, when the breakpoint
> +encountered has multiple locations, the field @samp{bkptno} is
> +followed by the field @samp{locno}.
> +
> +@smallexample
> +-exec-continue
> +^running
> +(gdb)
> +@@Hello world
> +*stopped,reason="breakpoint-hit",disp="keep",bkptno="2",locno="3",frame=@{
> +func="foo",args=[],file="hello.c",fullname="/home/foo/bar/hello.c",
> +line="13",arch="i386:x86_64"@}
> +(gdb)
> +@end smallexample
>  
> 
>  @subheading The @code{-exec-finish} Command
>  @findex -exec-finish
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 02c98b50c8c..e5ad062a914 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -8494,7 +8494,21 @@ print_stop_location (const target_waitstatus &ws)
>       LOCATION: Print only location
>       SRC_AND_LOC: Print location and source line.  */
>    if (do_frame_printing)
> -    print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    {
> +      if (tp->control.stop_bpstat != nullptr)
> +	{
> +	  const struct breakpoint *b = tp->control.stop_bpstat->breakpoint_at;
> +
> +	  if (b != nullptr)
> +	    {
> +	      int locno = bpstat_locno (tp->control.stop_bpstat);
> +	      set_internalvar_integer (lookup_internalvar ("bkptno"), b->number);
> +	      set_internalvar_integer (lookup_internalvar ("locno"),
> +				       (locno > 0 ? locno : 1));
> +	    }
> +	}
> +      print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    }
>  }
>  
> 
>  /* See infrun.h.  */
> diff --git a/gdb/testsuite/gdb.ada/bp_inlined_func.exp b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> index 076e8c2425f..3f94c163819 100644
> --- a/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> +++ b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> @@ -42,7 +42,7 @@ gdb_test "break read_small" \
>  for {set i 0} {$i < 4} {incr i} {
>      with_test_prefix "iteration $i" {
>  	gdb_test "continue" \
> -	    "Breakpoint $decimal, b\\.read_small \\(\\).*" \
> +	    "Breakpoint $bkptno_num_re, b\\.read_small \\(\\).*" \
>  	    "stopped in read_small"
>      }
>  }
> diff --git a/gdb/testsuite/gdb.ada/operator_bp.exp b/gdb/testsuite/gdb.ada/operator_bp.exp
> index 655e7af479f..e3928419ed6 100644
> --- a/gdb/testsuite/gdb.ada/operator_bp.exp
> +++ b/gdb/testsuite/gdb.ada/operator_bp.exp
> @@ -56,7 +56,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to \"$op\""
>  }
>  
> 
> @@ -86,7 +86,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to ops.\"$op\""
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> index b540df973a3..742315178e3 100644
> --- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> +++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> @@ -140,11 +140,11 @@ with_test_prefix "scenario 1" {
>      gdb_run_cmd
>  
> 
>      # Check our conditional breakpoints.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> @@ -208,11 +208,11 @@ with_test_prefix "scenario 2" {
>      gdb_run_cmd
>  
> 
>      # Check that we hit enabled locations only.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> diff --git a/gdb/testsuite/gdb.base/ctxobj.exp b/gdb/testsuite/gdb.base/ctxobj.exp
> index 9c010f54d79..0b589a7d6e6 100644
> --- a/gdb/testsuite/gdb.base/ctxobj.exp
> +++ b/gdb/testsuite/gdb.base/ctxobj.exp
> @@ -67,9 +67,16 @@ gdb_test "break ctxobj-f.c:$bp_location" \
>           "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
>           "break in get_version functions"
>  
> 
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_1 \\(\\).*" \
> -         "continue to get_version_1"
> +global expect_out
> +set test "continue to get_version_1"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_1 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  # Try printing "this_version_num".  There are two global variables
>  # with that name, and some systems such as GNU/Linux merge them
> @@ -100,10 +107,15 @@ gdb_test "print this_version_num == v" \
>          "print libctxobj1's this_version_num from symtab"
>  
> 
>  # Do the same, but from get_version_2.
> -
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_2 \\(\\).*" \
> -         "continue to get_version_2"
> +set test "continue to get_version_2"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_2 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  gdb_test "print this_version_num == v" \
>           " = 1" \
> diff --git a/gdb/testsuite/gdb.base/ena-dis-br.exp b/gdb/testsuite/gdb.base/ena-dis-br.exp
> index 24925cf7185..04b3f134b44 100644
> --- a/gdb/testsuite/gdb.base/ena-dis-br.exp
> +++ b/gdb/testsuite/gdb.base/ena-dis-br.exp
> @@ -67,14 +67,21 @@ gdb_test "info break $bp" \
>  # See the comments in condbreak.exp for "run until breakpoint at
>  # marker1" for an explanation of the xfail below.
>  set test "continue to break marker1"
> +set bpno 0
>  gdb_test_multiple "continue" "$test" {
> -    -re "Breakpoint \[0-9\]*, marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	pass "$test"
>      }
> -    -re "Breakpoint \[0-9\]*, $hex in marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), $hex in marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	xfail "$test"
>      }
>  }
> +# Verify the $bkptno convenience variable is equal to the hit bpno.
> +gdb_test "print \$bkptno" " = $bpno" "$test \$bkptno is $bpno"
> +# Verify the $locno is 1, as there is only one code location.
> +gdb_test "print \$locno" " = 1" "$test \$locno is 1"
>  
> 
>  gdb_test_no_output "delete $bp" "delete break marker1"
>  
> 
> @@ -359,7 +366,8 @@ with_test_prefix "4th breakpoint" {
>  }
>  
> 
>  # Perform tests for disable/enable commands on multiple
> -# locations and breakpoints.
> +# code locations and breakpoints.  If a breakpoint has only one code location,
> +# enable/disable num  and enable/disable num.1 should be equivalent.
>  #
>  # WHAT - the command to test (disable/enable).
>  #
> @@ -372,7 +380,7 @@ proc test_ena_dis_br { what } {
>      global b3
>      global b4
>      global gdb_prompt
> -    
> +
>      # OPPOS    - the command opposite to WHAT.
>      # WHAT_RES - whether breakpoints are expected to end
>      #            up enabled or disabled.
> @@ -395,13 +403,13 @@ proc test_ena_dis_br { what } {
>  	set p2 "pass"
>      }
>  
> 
> -    # Now enable(disable) $b.1 $b2.1.
> +    # Now enable(disable) $b1.1 $b2.1.
>      gdb_test_no_output "$what $b1.1 $b2.1" "$what \$b1.1 \$b2.1"
>      set test1 "${what}d \$b1.1 and \$b2.1"
>  
> 
>      # Now $b1.1 and $b2.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -       -re "(${b1}.1)(\[^\n\r\]*)( n.*)(${b2}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +       -re "(${b1})(\[^\n\r\]*)( n.*)(${b2})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> @@ -420,19 +428,16 @@ proc test_ena_dis_br { what } {
>         "${what}d \$b1"
>  
> 
>      gdb_test_no_output "$oppos $b3" "$oppos \$b3"
> +    # Now $b4 $b3 should be enabled(disabled)
> +    set test1 "${what}d \$b4 and \$b3"
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $oppos_res.*).*(${b4})(\[^\n\r\]*)( $oppos_res.*)" "$test1"
> +
>      gdb_test_no_output "$what $b4 $b3.1" "$what \$b4 \$b3.1"
> -    set test1 "${what}d \$b4 and \$b3.1,remain ${oppos}d \$b3"
> +    set test1 "${what}d \$b4 and \$b3.1, changing \$b3"
> +
> +    # Now $b4 $b3 should be enabled(disabled)
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $what_res.*).*(${b4})(\[^\n\r\]*)( $what_res.*)" "$test1"
>  
> 
> -    # Now $b4 $b3.1 should be enabled(disabled) and
> -    # $b3 should remain disabled(enabled).
> -    gdb_test_multiple "info break" "$test1" {
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b3}.1)(\[^\n\r\]*)( n.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p1 "$test1"
> -       }
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p2 "$test1"
> -       }
> -    }
>  
> 
>      # Now enable(disable) '$b4.1 fooobaar'.  This should error on
>      # fooobaar.
> @@ -443,7 +448,7 @@ proc test_ena_dis_br { what } {
>  
> 
>      # $b4.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -        -re "(${b4}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +        -re "(${b4})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.base/foll-exec-mode.exp b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> index 918f3e4fd5f..cb6d975a767 100644
> --- a/gdb/testsuite/gdb.base/foll-exec-mode.exp
> +++ b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> @@ -99,7 +99,7 @@ proc do_catch_exec_test { } {
>  # before re-running.
>  
> 
>  proc do_follow_exec_mode_tests { mode cmd infswitch } {
> -    global binfile srcfile srcfile2 testfile testfile2
> +    global binfile srcfile srcfile2 testfile testfile2 bkptno_numopt_re
>      global gdb_prompt
>  
> 
>      with_test_prefix "$mode,$cmd,$infswitch" {
> @@ -125,7 +125,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  	# Set up the output we expect to see after we execute past the exec.
>  	#
>  	set execd_line [gdb_get_line_number "after-exec" $srcfile2]
> -	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint .,.*${srcfile2}:${execd_line}.*$gdb_prompt $"
> +	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint ${bkptno_numopt_re},.*${srcfile2}:${execd_line}.*$gdb_prompt $"
>  
> 
>  	# Set a breakpoint after the exec call if we aren't single-stepping
>  	# past it.
> @@ -189,7 +189,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  		send_gdb "y\n"
>  		exp_continue
>  	    }
> -	    -re "Starting program: .*$expected_inf.*Breakpoint .,.*\r\n$gdb_prompt $" {
> +	    -re "Starting program: .*$expected_inf.*Breakpoint $bkptno_numopt_re,.*\r\n$gdb_prompt $" {
>  		pass $test
>  	    }
>  	}
> diff --git a/gdb/testsuite/gdb.base/pie-fork.exp b/gdb/testsuite/gdb.base/pie-fork.exp
> index efc357d39a2..19e9d3a5537 100644
> --- a/gdb/testsuite/gdb.base/pie-fork.exp
> +++ b/gdb/testsuite/gdb.base/pie-fork.exp
> @@ -54,10 +54,10 @@ proc_with_prefix test_detach_on_fork_follow_child {} {
>  proc_with_prefix test_no_detach_on_fork {} {
>      setup_test "off"
>  
> 
> -    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2.1, break_here.*" \
>  	     "continue from thread 1.1"
>      gdb_test "thread 2.1"
> -    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2.2, break_here.*" \
>  	     "continue from thread 2.1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/step-over-exit.exp b/gdb/testsuite/gdb.base/step-over-exit.exp
> index f8bd99980fe..575319c564c 100644
> --- a/gdb/testsuite/gdb.base/step-over-exit.exp
> +++ b/gdb/testsuite/gdb.base/step-over-exit.exp
> @@ -91,7 +91,7 @@ delete_breakpoints
>  
> 
>  gdb_test "break marker"
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_num_re, .*" \
>      "continue to marker, first time"
>  
> 
>  # Step 2, create a breakpoint which evaluates false, and force it
> @@ -120,5 +120,5 @@ gdb_test "inferior 1" ".*Switching to inferior 1.*" \
>  # Switch back to the parent process, continue to the marker to
>  # test GDBserver's state is still correct.
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_numopt_re, .*" \
>      "continue to marker, second time"
> diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
> index 47a2a5dcb7c..fa098602c31 100644
> --- a/gdb/testsuite/gdb.cp/mb-inline.exp
> +++ b/gdb/testsuite/gdb.cp/mb-inline.exp
> @@ -46,7 +46,7 @@ gdb_test "info break" \
>      "\[\r\n\]1\.1.* y .* at .*$hdrfile:$bp_location.*\[\r\n\]1\.2.* y .* at .*$hdrfile:$bp_location.*"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo \\(i=1\\).*" \
> @@ -59,7 +59,7 @@ gdb_test "continue" \
>  gdb_test_no_output "disable 1.2" "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
>  
> 
>  gdb_test_multiple "info break" "disabled breakpoint 1.2" {
>      -re "1\.2.* n .* at .*$hdrfile:$bp_location.*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
> index 6c988e7335e..0c0d46fcb7a 100644
> --- a/gdb/testsuite/gdb.cp/mb-templates.exp
> +++ b/gdb/testsuite/gdb.cp/mb-templates.exp
> @@ -42,7 +42,7 @@ gdb_run_cmd
>  
> 
>  set test "initial condition: run to breakpoint"
>  gdb_test_multiple "" $test {
> -    -re "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
> +    -re "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
>  	pass $test
>  	break
>      }
> @@ -67,7 +67,7 @@ gdb_test_no_output {condition $bpnum i==1} \
>      "separate condition: set condition"
>      
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo<double> \\(i=1\\).*" \
> @@ -79,7 +79,7 @@ gdb_test "continue" \
>  gdb_test_no_output {disable $bpnum.1} "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
>  
> 
>  # Try disabling entire breakpoint
>  gdb_test_no_output {enable $bpnum.1} "disabling location: enable"
> diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
> index 06adf82ecbb..0ed9eae055b 100644
> --- a/gdb/testsuite/gdb.cp/ovldbreak.exp
> +++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
> @@ -380,7 +380,7 @@ gdb_test "info break" $bptable "breakpoint info (after setting on all)"
>  
> 
>  # Run through each breakpoint.
>  proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
> -    global gdb_prompt hex decimal srcfile
> +    global gdb_prompt hex decimal srcfile bkptno_num_re
>  
> 
>      if {$argument == ""} {
>          set actuals ""
> @@ -398,11 +398,11 @@ proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
>      }
>  
> 
>      gdb_test_multiple "continue" "continue to bp overloaded : $argtype" {
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              pass "continue to bp overloaded : $argtype"
>          }
>  
> 
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              if $might_kfail {
>                  kfail "c++/8130" "continue to bp overloaded : $argtype"
>              } else {
> diff --git a/gdb/testsuite/gdb.gdb/python-helper.exp b/gdb/testsuite/gdb.gdb/python-helper.exp
> index 6db8bf0df50..30eb6038f3a 100644
> --- a/gdb/testsuite/gdb.gdb/python-helper.exp
> +++ b/gdb/testsuite/gdb.gdb/python-helper.exp
> @@ -49,7 +49,7 @@ gdb_exit
>  # The main test.  This is called by the self-test framework once GDB
>  # has been started on a copy of itself.
>  proc test_python_helper {} {
> -    global py_helper_script decimal hex gdb_prompt
> +    global py_helper_script decimal hex gdb_prompt bkptno_numopt_re
>      global inferior_spawn_id
>  
> 
>      # Source the python helper script.  This script registers the
> @@ -233,7 +233,7 @@ proc test_python_helper {} {
>      # GDB stopping at the value_print breakpoint again.
>      send_inferior "ptype global_c\n"
>      gdb_test_multiple "" "hit breakpoint in outer gdb again" {
> -	-re "Breakpoint $decimal, c_print_type .*\\(outer-gdb\\) $" {
> +	-re "Breakpoint $bkptno_numopt_re, c_print_type .*\\(outer-gdb\\) $" {
>  	    pass $gdb_test_name
>  	}
>      }
> diff --git a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> index 19ccbe85e04..c080955049c 100644
> --- a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> +++ b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> @@ -69,7 +69,7 @@ if { $use_second_inferior } {
>  	"\\^running.*" \
>  	"run inferior 2"
>  
> 
> -    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\""} \
> +    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\"" "locno=\"[0-9]+\""} \
>  	"inferior i2 stops at all_threads_started"
>  
> 
>      mi_send_resuming_command "exec-continue --thread-group i2" \
> diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> index d78c96ddef1..9eec083068b 100644
> --- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> +++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> @@ -307,8 +307,13 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  	    # Consume MI event output.
>  	    with_spawn_id $mi_spawn_id {
> -		mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> -		    "$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		if { $inf == 1 } {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		} else {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} "stop at breakpoint in main"
> +		}
>  	    }
>  
> 
>  	    if { $mode == "all-stop" } {
> @@ -330,9 +335,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		    # Consume MI output.
>  		    with_spawn_id $mi_spawn_id {
> -			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			    "thread $inf.$thread stops MI"
> +			if { $inf == 1} {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +				"thread $inf.$thread stops MI"
> +			} else {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +				"thread $inf.$thread stops MI"
> +			}
>  		    }
>  		}
>  
> 
> @@ -359,9 +370,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		# Consume MI output.
>  		with_spawn_id $mi_spawn_id {
> -		    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			"thread $inf.2 stops MI"
> +		    if { $inf == 1} {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +			    "thread $inf.2 stops MI"
> +		    } else {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +			    "thread $inf.2 stops MI"
> +		    }
>  		}
>  	    }
>  	}
> @@ -434,7 +451,7 @@ proc_with_prefix test_setup { mode } {
>  
> 
>  	with_spawn_id $mi_spawn_id {
>  	    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" "$decimal" \
> -		{"" "disp=\"del\""} "main stop"
> +		{"" "disp=\"del\"" "locno=\"[0-9]+\""} "main stop"
>  	}
>  
> 
>  	# Consume CLI output.
> diff --git a/gdb/testsuite/gdb.multi/multi-arch-exec.exp b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> index a1496fb5571..dfdb746c65e 100644
> --- a/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> +++ b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> @@ -148,6 +148,7 @@ proc build_executables { first_arch } {
>  }
>  
> 
>  proc do_test { first_arch mode selected_thread } {
> +        global bkptno_numopt_re
>  	set from_exec "$first_arch-multi-arch-exec"
>  
> 
>  	clean_restart ${from_exec}
> @@ -169,7 +170,7 @@ proc do_test { first_arch mode selected_thread } {
>  
> 
>  	# Test that GDB updates the target description / arch successfuly
>  	# after the exec.
> -	gdb_test "continue" "Breakpoint 2, main.*" "continue across exec that changes architecture"
> +	gdb_test "continue" "Breakpoint $bkptno_numopt_re, main.*" "continue across exec that changes architecture"
>  }
>  
> 
>  # Test both arch1=>arch2 and arch2=>arch1.
> diff --git a/gdb/testsuite/gdb.multi/run-only-second-inf.exp b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> index fec2575f904..b94689d0bfa 100644
> --- a/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> +++ b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> @@ -46,5 +46,5 @@ gdb_load $binfile
>  if {[gdb_start_cmd] < 0} {
>      fail "start the second inf"
>  } else {
> -    gdb_test "" ".*reakpoint ., main .*${srcfile}.*" "start the second inf"
> +    gdb_test "" ".*reakpoint $bkptno_numopt_re, main .*${srcfile}.*" "start the second inf"
>  }
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> index cbccba19d12..3c079facced 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> @@ -27,7 +27,7 @@ if {[build_executable "failed to build" $testfile $srcfile {debug}]} {
>  # child.  Can be either "kill", "detach", or "exit" (to continue it to
>  # normal exit).
>  proc do_test {dispose} {
> -    global binfile
> +    global binfile bkptno_numopt_re
>  
> 
>      clean_restart $binfile
>  
> 
> @@ -77,7 +77,7 @@ proc do_test {dispose} {
>      #  Command aborted.
>      #  (gdb)
>      #
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker .*" \
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker .*" \
>  	"continue in inferior 1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi.exp b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> index e4329dca6c2..0fc1bee762f 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> @@ -84,11 +84,11 @@ if [skip_hw_watchpoint_multi_tests] {
>  	"Hardware access \\(read/write\\) watchpoint \[0-9\]+: c\r\n\r\nOld value = 0\r\nNew value = 3\r\n.*" \
>  	"catch c on inferior 2"
>  
> 
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 2"
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 2"
>  
> 
>      gdb_test "inferior 1" "witching to inferior 1 .*" "switch back to inferior 1 again"
>  
> 
>      gdb_test "continue" "Hardware access \\(read/write\\) watchpoint \[0-9\]+: b\r\n\r\nOld value = 0\r\nNew value = 2\r\n.*" "catch b on inferior 1"
>  }
>  
> 
> -gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 1"
> +gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 1"
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 402450152ac..5e4c793598e 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -227,6 +227,14 @@ set inferior_exited_re "(?:\\\[Inferior \[0-9\]+ \\(\[^\n\r\]*\\) exited)"
>  # E.g., $1, $2, etc.
>  set valnum_re "\\\$$decimal"
>  
> 
> +# A regular expression that matches a breakpoint hit with a breakpoint
> +# having several code locations.
> +set bkptno_num_re "$decimal\\.$decimal"
> +
> +# A regular expression that matches a breakpoint hit
> +# with one or several code locations.
> +set bkptno_numopt_re "($decimal\\.$decimal|$decimal)"
> +
>  ### Only procedures should come after this point.
>  
> 
>  #
> @@ -662,6 +670,7 @@ proc gdb_breakpoint { linespec args } {
>  
> 
>  proc runto { linespec args } {
>      global gdb_prompt
> +    global bkptno_numopt_re
>      global decimal
>  
> 
>      delete_breakpoints
> @@ -699,7 +708,7 @@ proc runto { linespec args } {
>  	    }
>  	    return 1
>  	}
> -	-re "Breakpoint \[0-9\]*, \[0-9xa-f\]* in .*$gdb_prompt $" { 
> +	-re "Breakpoint $bkptno_numopt_re, \[0-9xa-f\]* in .*$gdb_prompt $" {
>  	    if { $print_pass } {
>  		pass $test_name
>  	    }
> diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
> index e578a7e6f9b..ea66fdcabf8 100644
> --- a/gdb/testsuite/lib/mi-support.exp
> +++ b/gdb/testsuite/lib/mi-support.exp
> @@ -1195,11 +1195,11 @@ proc mi_detect_async {} {
>  # filename of a file without debug info.  ARGS should not include [] the
>  # list of argument is enclosed in, and other regular expressions should
>  # not include quotes.
> -# If EXTRA is a list of one element, it's the regular expression
> +# EXTRA can be a list of one, two or three elements.
> +# The first element is the regular expression
>  # for output expected right after *stopped, and before GDB prompt.
> -# If EXTRA is a list of two elements, the first element is for
> -# output right after *stopped, and the second element is output
> -# right after reason field.  The regex after reason should not include
> +# The third element is the regulation expression for the locno
> +# right after bkptno field.  The locno regex should not include
>  # the comma separating it from the following fields.
>  #
>  # When we fail to match output at all, -1 is returned.  If FILE does
> @@ -1224,7 +1224,14 @@ proc mi_expect_stop { reason func args file line extra test } {
>  
> 
>      set after_stopped ""
>      set after_reason ""
> -    if { [llength $extra] == 2 } {
> +    set locno ""
> +    if { [llength $extra] == 3 } {
> +	set after_stopped [lindex $extra 0]
> +	set after_reason [lindex $extra 1]
> +	set after_reason "${after_reason},"
> +	set locno [lindex $extra 2]
> +	set locno "${locno},"
> +    } elseif { [llength $extra] == 2 } {
>  	set after_stopped [lindex $extra 0]
>  	set after_reason [lindex $extra 1]
>  	set after_reason "${after_reason},"
> @@ -1298,10 +1305,12 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set ebn ""
>      if { $reason == "breakpoint-hit" } {
>  	set bn {bkptno="[0-9]+",}
> +	set bn "${bn}${locno}"
>      } elseif { $reason == "solib-event" } {
>  	set bn ".*"
>      } elseif { $reason == "exception-caught" } {
>  	set ebn {bkptno="[0-9]+",}
> +	set ebn "${ebn}${locno}"
>  	set bn ".*"
>  	set reason "breakpoint-hit"
>      }
> @@ -1315,6 +1324,7 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set a $after_reason
>  
> 
>      verbose -log "mi_expect_stop: expecting: \\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
> +
>      gdb_expect {
>  	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
>  	    pass "$test"



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-06-06  9:45 [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno Philippe Waroquiers
                   ` (8 preceding siblings ...)
  2022-08-21 12:05 ` Philippe Waroquiers
@ 2022-08-27 14:45 ` Philippe Waroquiers
  2022-09-03 15:17 ` ping^10 " Philippe Waroquiers
  2022-11-10 15:57 ` Tom Tromey
  11 siblings, 0 replies; 17+ messages in thread
From: Philippe Waroquiers @ 2022-08-27 14:45 UTC (permalink / raw)
  To: gdb-patches

Ping ^ 9
(Eli reviewed the doc, Keith did a first code review)

Thanks
Philippe

On Mon, 2022-06-06 at 11:45 +0200, Philippe Waroquiers wrote:
> Before this patch, when a breakpoint that has multiple locations is reached,
> GDB printed:
>   Thread 1 "zeoes" hit Breakpoint 1, some_func () at somefunc1.c:5
> 
> This patch changes the message so that bkpt_print_id prints the precise
> encountered breakpoint:
>   Thread 1 "zeoes" hit Breakpoint 1.2, some_func () at somefunc1.c:5
> 
> In mi mode, bkpt_print_id also (optionally) prints a new table field "locno":
>   locno is printed when the breakpoint has more than one location.
> Note that according to the GDB user manual node 'GDB/MI Development and Front
> Ends', it is ok to add new fields without changing the MI version.
> 
> Also, when a breakpoint is reached, the convenience variables
> $bkptno and $locno are set to the encountered breakpoint number
> and location number.
> 
> $bkptno and $locno can a.o. be used in the command list of a breakpoint,
> to disable the specific encountered breakpoint, e.g.
>    disable $bkptno.$locno
> 
> In case the breakpoint has only one location, $locno is still set to
> the value 1, so as to allow a command such as:
>   disable $bkptno.$locno
> even when the breakpoint has only one location.
> 
> This also fixes a strange behaviour: when a breakpoint X has only
> one location,
>   enable|disable X.1
> is accepted but transforms the breakpoint in a multiple locations
> breakpoint having only one location.
> 
> The changes in RFA v3 handle the additional comments of Eli:
>  GDB/NEW:
>   - Use max 80-column
>   - Use 'code location' instead of 'location'.
>   - Fix typo $bkpno
>   - Ensure that disable $bkptno and disable $bkptno.$locno have
>     each their explanation inthe example
>   - Reworded the 'breakpoint-hit' paragraph.
>  gdb.texinfo:
>   - Use 'code location' instead of 'location'.
>   - Add a note to clarify the distinction between $bkptno and $bpnum.
>   - Use @kbd instead of examples with only one command.
> 
> Compared to RFA v1, the changes in v2 handle the comments given by
> Keith Seitz and Eli Zaretskii:
>   - Use %s for the result of paddress
>   - Use bkptno_numopt_re instead of 2 different -re cases
>   - use C@t{++}
>   - Add index entries for $bkptno and $locno
>   - Added an example for "locno" in the mi interface
>   - Added examples in the Break command manual.
> ---
>  gdb/NEWS                                      | 21 +++++
>  gdb/ada-lang.c                                |  2 +-
>  gdb/break-catch-syscall.c                     |  2 +-
>  gdb/break-catch-throw.c                       |  2 +-
>  gdb/breakpoint.c                              | 93 +++++++++++++++----
>  gdb/breakpoint.h                              | 14 +++
>  gdb/doc/gdb.texinfo                           | 83 ++++++++++++++++-
>  gdb/infrun.c                                  | 16 +++-
>  gdb/testsuite/gdb.ada/bp_inlined_func.exp     |  2 +-
>  gdb/testsuite/gdb.ada/operator_bp.exp         |  4 +-
>  .../gdb.base/condbreak-multi-context.exp      |  8 +-
>  gdb/testsuite/gdb.base/ctxobj.exp             | 26 ++++--
>  gdb/testsuite/gdb.base/ena-dis-br.exp         | 41 ++++----
>  gdb/testsuite/gdb.base/foll-exec-mode.exp     |  6 +-
>  gdb/testsuite/gdb.base/pie-fork.exp           |  4 +-
>  gdb/testsuite/gdb.base/step-over-exit.exp     |  4 +-
>  gdb/testsuite/gdb.cp/mb-inline.exp            |  4 +-
>  gdb/testsuite/gdb.cp/mb-templates.exp         |  6 +-
>  gdb/testsuite/gdb.cp/ovldbreak.exp            |  6 +-
>  gdb/testsuite/gdb.gdb/python-helper.exp       |  4 +-
>  .../gdb.mi/interrupt-thread-group.exp         |  2 +-
>  .../gdb.mi/user-selected-context-sync.exp     | 35 +++++--
>  gdb/testsuite/gdb.multi/multi-arch-exec.exp   |  3 +-
>  .../gdb.multi/run-only-second-inf.exp         |  2 +-
>  .../gdb.multi/watchpoint-multi-exit.exp       |  4 +-
>  gdb/testsuite/gdb.multi/watchpoint-multi.exp  |  4 +-
>  gdb/testsuite/lib/gdb.exp                     | 11 ++-
>  gdb/testsuite/lib/mi-support.exp              | 20 +++-
>  28 files changed, 335 insertions(+), 94 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 960f90b4387..a5602deee2b 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -34,6 +34,21 @@
>       whitespace from each line before using the string as the help
>       output.
>  
> 
> +* When a breakpoint with multiple code locations is hit, GDB now prints
> +  the code location using the syntax <breakpoint_number>.<location_number>
> +  such as in:
> +     Thread 1 "zeoes" hit Breakpoint 2.3, some_func () at zeoes.c:8
> +
> +* When a breakpoint is hit, GDB now sets the convenience variables $bkptno and
> +  $locno to the hit breakpoint number and code location number.
> +  This allows to disable the last hit breakpoint using
> +     (gdb) disable $bkptno
> +   or disable only the specific breakpoint code location using
> +     (gdb) disable $bkptno.$locno
> +  These commands can be used inside the command list of a breakpoint to
> +  automatically disable the just encountered breakpoint (or the just
> +  encountered specific breakpoint code location).
> +
>  * New commands
>  
> 
>  maintenance set ignore-prologue-end-flag on|off
> @@ -50,6 +65,12 @@ maintenance info line-table
>    entry corresponds to an address where a breakpoint should be placed
>    to be at the first instruction past a function's prologue.
>  
> 
> +* MI changes
> +
> + ** The async record stating the stopped reason 'breakpoint-hit' now
> +    contains an optional field locno giving the code location number
> +    when the breakpoint has multiple code locations.
> +
>  * Python API
>  
> 
>    ** New function gdb.format_address(ADDRESS, PROGSPACE, ARCHITECTURE),
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 6ab01fd27d4..bbae76f39ac 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -12348,7 +12348,7 @@ ada_catchpoint::print_it (const bpstat *bs) const
>  
> 
>    uiout->text (disposition == disp_del
>  	       ? "\nTemporary catchpoint " : "\nCatchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    /* ada_exception_name_addr relies on the selected frame being the
> diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
> index 06d48466de7..82229de33f7 100644
> --- a/gdb/break-catch-syscall.c
> +++ b/gdb/break-catch-syscall.c
> @@ -218,7 +218,7 @@ syscall_catchpoint::print_it (const bpstat *bs) const
>  						: EXEC_ASYNC_SYSCALL_RETURN));
>        uiout->field_string ("disp", bpdisp_text (b->disposition));
>      }
> -  uiout->field_signed ("bkptno", b->number);
> +  print_num_locno (bs, uiout);
>  
> 
>    if (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY)
>      uiout->text (" (call to syscall ");
> diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
> index 66cf80be1c5..5b6f5d9eca1 100644
> --- a/gdb/break-catch-throw.c
> +++ b/gdb/break-catch-throw.c
> @@ -257,7 +257,7 @@ exception_catchpoint::print_it (const bpstat *bs) const
>    bp_temp = disposition == disp_del;
>    uiout->text (bp_temp ? "Temporary catchpoint "
>  		       : "Catchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text ((kind == EX_EVENT_THROW ? " (exception thrown), "
>  		: (kind == EX_EVENT_CATCH ? " (exception caught), "
>  		   : " (exception rethrown), ")));
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index ed932a19ed7..c89c800f32f 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -820,6 +820,19 @@ get_breakpoint (int num)
>    return nullptr;
>  }
>  
> 
> +/* Return TRUE if NUM refer to an existing breakpoint that has
> +   multiple code locations.  */
> +
> +static bool
> +has_multiple_locations (int num)
> +{
> +  for (breakpoint *b : all_breakpoints ())
> +    if (b->number == num)
> +      return b->loc != nullptr && b->loc->next != nullptr;
> +
> +  return false;
> +}
> +
>  \f
>  
> 
>  /* Mark locations as "conditions have changed" in case the target supports
> @@ -4451,15 +4464,7 @@ bpstat_explains_signal (bpstat *bsp, enum gdb_signal sig)
>    return false;
>  }
>  
> 
> -/* Put in *NUM the breakpoint number of the first breakpoint we are
> -   stopped at.  *BSP upon return is a bpstat which points to the
> -   remaining breakpoints stopped at (but which is not guaranteed to be
> -   good for anything but further calls to bpstat_num).
> -
> -   Return 0 if passed a bpstat which does not indicate any breakpoints.
> -   Return -1 if stopped at a breakpoint that has been deleted since
> -   we set it.
> -   Return 1 otherwise.  */
> +/* See breakpoint.h.  */
>  
> 
>  int
>  bpstat_num (bpstat **bsp, int *num)
> @@ -4481,6 +4486,57 @@ bpstat_num (bpstat **bsp, int *num)
>    return 1;
>  }
>  
> 
> +/* See breakpoint.h  */
> +
> +int
> +bpstat_locno (const bpstat *bs)
> +{
> +  const struct breakpoint *b = bs->breakpoint_at;
> +  const struct bp_location *bl = bs->bp_location_at.get ();
> +
> +  int locno = 0;
> +
> +  if (b != nullptr && b->loc->next != nullptr)
> +    {
> +      const bp_location *bl_i;
> +
> +      for (bl_i = b->loc;
> +	   bl_i != bl && bl_i->next != nullptr;
> +	   bl_i = bl_i->next)
> +	locno++;
> +
> +      if (bl_i == bl)
> +	locno++;
> +      else
> +	{
> +	  warning (_("location number not found for breakpoint %d address %s."),
> +		   b->number, paddress (bl->gdbarch, bl->address));
> +	  locno = 0;
> +	}
> +    }
> +
> +  return locno;
> +}
> +
> +/* See breakpoint.h.  */
> +
> +void
> +print_num_locno (const bpstat *bs, struct ui_out *uiout)
> +{
> +  struct breakpoint *b = bs->breakpoint_at;
> +
> +  if (b == nullptr)
> +    uiout->text (_("deleted breakpoint"));
> +  else
> +    {
> +      uiout->field_signed ("bkptno", b->number);
> +
> +      int locno = bpstat_locno (bs);
> +      if (locno != 0)
> +	uiout->message (".%pF", signed_field ("locno", locno));
> +    }
> +}
> +
>  /* See breakpoint.h.  */
>  
> 
>  void
> @@ -9176,7 +9232,7 @@ ranged_breakpoint::print_it (const bpstat *bs) const
>  		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
> @@ -11610,12 +11666,13 @@ ordinary_breakpoint::print_it (const bpstat *bs) const
>  			   async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> +
>    if (bp_temp)
> -    uiout->message ("Temporary breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Temporary breakpoint ");
>    else
> -    uiout->message ("Breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Breakpoint ");
> +  print_num_locno (bs, uiout);
> +  uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
>  }
> @@ -13220,9 +13277,13 @@ enable_disable_command (const char *args, int from_tty, bool enable)
>  	  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)
> +	      && (bp_loc_range.first == 0
> +		  || (bp_loc_range.first == 1
> +		      && bp_num_range.first == bp_num_range.second
> +		      && !has_multiple_locations (bp_num_range.first))))
>  	    {
> -	      /* Handle breakpoint ids with formats 'x' or 'x-z'.  */
> +	      /* Handle breakpoint ids with formats 'x' or 'x-z'
> +		 or 'y.1' where y has only one code location.  */
>  	      map_breakpoint_number_range (bp_num_range,
>  					   enable
>  					   ? enable_breakpoint
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 566f1285e46..96d61ef5427 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -1231,6 +1231,20 @@ extern enum print_stop_action bpstat_print (bpstat *, int);
>     Return 1 otherwise.  */
>  extern int bpstat_num (bpstat **, int *);
>  
> 
> +/* If BS indicates a breakpoint and this breakpoint has several code locations,
> +   return the location number of BS, otherwise return 0.  */
> +
> +extern int bpstat_locno (const bpstat *bs);
> +
> +/* Print BS breakpoint number optionally followed by a . and breakpoint locno.
> +
> +   For a breakpoint with only one code location, outputs the signed field
> +   "bkptno" breakpoint number of BS (as returned by bpstat_num).
> +   If BS has several code locations, outputs a '.' character followed by
> +   the signed field "locno" (as returned by bpstat_locno).  */
> +
> +extern void print_num_locno (const bpstat *bs, struct ui_out *);
> +
>  /* Perform actions associated with the stopped inferior.  Actually, we
>     just use this for breakpoint commands.  Perhaps other actions will
>     go here later, but this is executed at a late time (from the
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 434add3a663..391b81f8863 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -4338,9 +4338,65 @@ are operated on.
>  @cindex latest breakpoint
>  Breakpoints are set with the @code{break} command (abbreviated
>  @code{b}).  The debugger convenience variable @samp{$bpnum} records the
> -number of the breakpoint you've set most recently; see @ref{Convenience
> -Vars,, Convenience Variables}, for a discussion of what you can do with
> -convenience variables.
> +number of the breakpoint you've set most recently:
> +@smallexample
> +(gdb) b main
> +Breakpoint 1 at 0x11c6: file zeoes.c, line 24.
> +(gdb) p $bpnum
> +$1 = 1
> +@end smallexample
> +
> +A breakpoint may be mapped to multiple code locations for example with
> +inlined functions, Ada generics, C@t{++} templates or overloaded function names.
> +@value{GDBN} then indicates the number of code locations in the breakpoint
> +command output:
> +@smallexample
> +(gdb) b some_func
> +Breakpoint 2 at 0x1179: some_func. (3 locations)
> +(gdb) p $bpnum
> +$2 = 2
> +(gdb)
> +@end smallexample
> +
> +@vindex $bkptno@r{, convenience variable}
> +@vindex $locno@r{, convenience variable}
> +When your program stops on a breakpoint, the convenience variables
> +@samp{$bkptno} and @samp{$locno} are respectively set to the number of
> +the encountered breakpoint and the number of the breakpoint's code location:
> +@smallexample
> +Thread 1 "zeoes" hit Breakpoint 2.1, some_func () at zeoes.c:8
> +8	  printf("some func\n");
> +(gdb) p $bkptno
> +$5 = 2
> +(gdb) p $locno
> +$6 = 1
> +(gdb)
> +@end smallexample
> +
> +Note that @samp{$bkptno} and @samp{$bpnum} are not equivalent:
> +@samp{$bkptno} is set to the breakpoint number @b{last hit}, while
> +@samp{$bpnum} is set to the breakpoint number @b{last set}.
> +
> +
> +If the encountered breakpoint has only one code location, @samp{$locno} is set
> +to 1:
> +@smallexample
> +Breakpoint 1, main (argc=1, argv=0x7fffffffe018) at zeoes.c:24
> +24	  if (argc > 1)
> +(gdb) p $bkptno
> +$3 = 1
> +(gdb) p $locno
> +$4 = 1
> +(gdb)
> +@end smallexample
> +
> +The @samp{$bkptno} and @samp{$locno} variables can typically be used
> +in a breakpoint command list.
> +(@pxref{Break Commands, ,Breakpoint Command Lists}). For example, as
> +part of the breakpoint command list, you can disable completely the
> +encountered breakpoint using @samp{disable $bkptno} or disable the
> +specific encountered breakpoint location using @samp{disable
> +$bkptno.$locno}.
>  
> 
>  @table @code
>  @item break @var{locspec}
> @@ -5739,6 +5795,13 @@ Expressions}).
>  Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
>  disabled within a @var{command-list}.
>  
> 
> +Inside a command list, you can use the command
> +@kbd{disable $bkptno} to disable the encountered breakpoint.
> +
> +If your breakpoint has several code locations, the command
> +@kbd{disable $bkptno.$locno} will disable the specific breakpoint code
> +location encountered.
> +
>  You can use breakpoint commands to start your program up again.  Simply
>  use the @code{continue} command, or @code{step}, or any other command
>  that resumes execution.
> @@ -32570,6 +32633,20 @@ line="13",arch="i386:x86_64"@}
>  (gdb)
>  @end smallexample
>  
> 
> +For a @samp{breakpoint-hit} stopped reason, when the breakpoint
> +encountered has multiple locations, the field @samp{bkptno} is
> +followed by the field @samp{locno}.
> +
> +@smallexample
> +-exec-continue
> +^running
> +(gdb)
> +@@Hello world
> +*stopped,reason="breakpoint-hit",disp="keep",bkptno="2",locno="3",frame=@{
> +func="foo",args=[],file="hello.c",fullname="/home/foo/bar/hello.c",
> +line="13",arch="i386:x86_64"@}
> +(gdb)
> +@end smallexample
>  
> 
>  @subheading The @code{-exec-finish} Command
>  @findex -exec-finish
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 02c98b50c8c..e5ad062a914 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -8494,7 +8494,21 @@ print_stop_location (const target_waitstatus &ws)
>       LOCATION: Print only location
>       SRC_AND_LOC: Print location and source line.  */
>    if (do_frame_printing)
> -    print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    {
> +      if (tp->control.stop_bpstat != nullptr)
> +	{
> +	  const struct breakpoint *b = tp->control.stop_bpstat->breakpoint_at;
> +
> +	  if (b != nullptr)
> +	    {
> +	      int locno = bpstat_locno (tp->control.stop_bpstat);
> +	      set_internalvar_integer (lookup_internalvar ("bkptno"), b->number);
> +	      set_internalvar_integer (lookup_internalvar ("locno"),
> +				       (locno > 0 ? locno : 1));
> +	    }
> +	}
> +      print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    }
>  }
>  
> 
>  /* See infrun.h.  */
> diff --git a/gdb/testsuite/gdb.ada/bp_inlined_func.exp b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> index 076e8c2425f..3f94c163819 100644
> --- a/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> +++ b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> @@ -42,7 +42,7 @@ gdb_test "break read_small" \
>  for {set i 0} {$i < 4} {incr i} {
>      with_test_prefix "iteration $i" {
>  	gdb_test "continue" \
> -	    "Breakpoint $decimal, b\\.read_small \\(\\).*" \
> +	    "Breakpoint $bkptno_num_re, b\\.read_small \\(\\).*" \
>  	    "stopped in read_small"
>      }
>  }
> diff --git a/gdb/testsuite/gdb.ada/operator_bp.exp b/gdb/testsuite/gdb.ada/operator_bp.exp
> index 655e7af479f..e3928419ed6 100644
> --- a/gdb/testsuite/gdb.ada/operator_bp.exp
> +++ b/gdb/testsuite/gdb.ada/operator_bp.exp
> @@ -56,7 +56,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to \"$op\""
>  }
>  
> 
> @@ -86,7 +86,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to ops.\"$op\""
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> index b540df973a3..742315178e3 100644
> --- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> +++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> @@ -140,11 +140,11 @@ with_test_prefix "scenario 1" {
>      gdb_run_cmd
>  
> 
>      # Check our conditional breakpoints.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> @@ -208,11 +208,11 @@ with_test_prefix "scenario 2" {
>      gdb_run_cmd
>  
> 
>      # Check that we hit enabled locations only.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> diff --git a/gdb/testsuite/gdb.base/ctxobj.exp b/gdb/testsuite/gdb.base/ctxobj.exp
> index 9c010f54d79..0b589a7d6e6 100644
> --- a/gdb/testsuite/gdb.base/ctxobj.exp
> +++ b/gdb/testsuite/gdb.base/ctxobj.exp
> @@ -67,9 +67,16 @@ gdb_test "break ctxobj-f.c:$bp_location" \
>           "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
>           "break in get_version functions"
>  
> 
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_1 \\(\\).*" \
> -         "continue to get_version_1"
> +global expect_out
> +set test "continue to get_version_1"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_1 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  # Try printing "this_version_num".  There are two global variables
>  # with that name, and some systems such as GNU/Linux merge them
> @@ -100,10 +107,15 @@ gdb_test "print this_version_num == v" \
>          "print libctxobj1's this_version_num from symtab"
>  
> 
>  # Do the same, but from get_version_2.
> -
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_2 \\(\\).*" \
> -         "continue to get_version_2"
> +set test "continue to get_version_2"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_2 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  gdb_test "print this_version_num == v" \
>           " = 1" \
> diff --git a/gdb/testsuite/gdb.base/ena-dis-br.exp b/gdb/testsuite/gdb.base/ena-dis-br.exp
> index 24925cf7185..04b3f134b44 100644
> --- a/gdb/testsuite/gdb.base/ena-dis-br.exp
> +++ b/gdb/testsuite/gdb.base/ena-dis-br.exp
> @@ -67,14 +67,21 @@ gdb_test "info break $bp" \
>  # See the comments in condbreak.exp for "run until breakpoint at
>  # marker1" for an explanation of the xfail below.
>  set test "continue to break marker1"
> +set bpno 0
>  gdb_test_multiple "continue" "$test" {
> -    -re "Breakpoint \[0-9\]*, marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	pass "$test"
>      }
> -    -re "Breakpoint \[0-9\]*, $hex in marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), $hex in marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	xfail "$test"
>      }
>  }
> +# Verify the $bkptno convenience variable is equal to the hit bpno.
> +gdb_test "print \$bkptno" " = $bpno" "$test \$bkptno is $bpno"
> +# Verify the $locno is 1, as there is only one code location.
> +gdb_test "print \$locno" " = 1" "$test \$locno is 1"
>  
> 
>  gdb_test_no_output "delete $bp" "delete break marker1"
>  
> 
> @@ -359,7 +366,8 @@ with_test_prefix "4th breakpoint" {
>  }
>  
> 
>  # Perform tests for disable/enable commands on multiple
> -# locations and breakpoints.
> +# code locations and breakpoints.  If a breakpoint has only one code location,
> +# enable/disable num  and enable/disable num.1 should be equivalent.
>  #
>  # WHAT - the command to test (disable/enable).
>  #
> @@ -372,7 +380,7 @@ proc test_ena_dis_br { what } {
>      global b3
>      global b4
>      global gdb_prompt
> -    
> +
>      # OPPOS    - the command opposite to WHAT.
>      # WHAT_RES - whether breakpoints are expected to end
>      #            up enabled or disabled.
> @@ -395,13 +403,13 @@ proc test_ena_dis_br { what } {
>  	set p2 "pass"
>      }
>  
> 
> -    # Now enable(disable) $b.1 $b2.1.
> +    # Now enable(disable) $b1.1 $b2.1.
>      gdb_test_no_output "$what $b1.1 $b2.1" "$what \$b1.1 \$b2.1"
>      set test1 "${what}d \$b1.1 and \$b2.1"
>  
> 
>      # Now $b1.1 and $b2.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -       -re "(${b1}.1)(\[^\n\r\]*)( n.*)(${b2}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +       -re "(${b1})(\[^\n\r\]*)( n.*)(${b2})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> @@ -420,19 +428,16 @@ proc test_ena_dis_br { what } {
>         "${what}d \$b1"
>  
> 
>      gdb_test_no_output "$oppos $b3" "$oppos \$b3"
> +    # Now $b4 $b3 should be enabled(disabled)
> +    set test1 "${what}d \$b4 and \$b3"
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $oppos_res.*).*(${b4})(\[^\n\r\]*)( $oppos_res.*)" "$test1"
> +
>      gdb_test_no_output "$what $b4 $b3.1" "$what \$b4 \$b3.1"
> -    set test1 "${what}d \$b4 and \$b3.1,remain ${oppos}d \$b3"
> +    set test1 "${what}d \$b4 and \$b3.1, changing \$b3"
> +
> +    # Now $b4 $b3 should be enabled(disabled)
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $what_res.*).*(${b4})(\[^\n\r\]*)( $what_res.*)" "$test1"
>  
> 
> -    # Now $b4 $b3.1 should be enabled(disabled) and
> -    # $b3 should remain disabled(enabled).
> -    gdb_test_multiple "info break" "$test1" {
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b3}.1)(\[^\n\r\]*)( n.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p1 "$test1"
> -       }
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p2 "$test1"
> -       }
> -    }
>  
> 
>      # Now enable(disable) '$b4.1 fooobaar'.  This should error on
>      # fooobaar.
> @@ -443,7 +448,7 @@ proc test_ena_dis_br { what } {
>  
> 
>      # $b4.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -        -re "(${b4}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +        -re "(${b4})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.base/foll-exec-mode.exp b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> index 918f3e4fd5f..cb6d975a767 100644
> --- a/gdb/testsuite/gdb.base/foll-exec-mode.exp
> +++ b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> @@ -99,7 +99,7 @@ proc do_catch_exec_test { } {
>  # before re-running.
>  
> 
>  proc do_follow_exec_mode_tests { mode cmd infswitch } {
> -    global binfile srcfile srcfile2 testfile testfile2
> +    global binfile srcfile srcfile2 testfile testfile2 bkptno_numopt_re
>      global gdb_prompt
>  
> 
>      with_test_prefix "$mode,$cmd,$infswitch" {
> @@ -125,7 +125,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  	# Set up the output we expect to see after we execute past the exec.
>  	#
>  	set execd_line [gdb_get_line_number "after-exec" $srcfile2]
> -	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint .,.*${srcfile2}:${execd_line}.*$gdb_prompt $"
> +	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint ${bkptno_numopt_re},.*${srcfile2}:${execd_line}.*$gdb_prompt $"
>  
> 
>  	# Set a breakpoint after the exec call if we aren't single-stepping
>  	# past it.
> @@ -189,7 +189,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  		send_gdb "y\n"
>  		exp_continue
>  	    }
> -	    -re "Starting program: .*$expected_inf.*Breakpoint .,.*\r\n$gdb_prompt $" {
> +	    -re "Starting program: .*$expected_inf.*Breakpoint $bkptno_numopt_re,.*\r\n$gdb_prompt $" {
>  		pass $test
>  	    }
>  	}
> diff --git a/gdb/testsuite/gdb.base/pie-fork.exp b/gdb/testsuite/gdb.base/pie-fork.exp
> index efc357d39a2..19e9d3a5537 100644
> --- a/gdb/testsuite/gdb.base/pie-fork.exp
> +++ b/gdb/testsuite/gdb.base/pie-fork.exp
> @@ -54,10 +54,10 @@ proc_with_prefix test_detach_on_fork_follow_child {} {
>  proc_with_prefix test_no_detach_on_fork {} {
>      setup_test "off"
>  
> 
> -    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2.1, break_here.*" \
>  	     "continue from thread 1.1"
>      gdb_test "thread 2.1"
> -    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2.2, break_here.*" \
>  	     "continue from thread 2.1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/step-over-exit.exp b/gdb/testsuite/gdb.base/step-over-exit.exp
> index f8bd99980fe..575319c564c 100644
> --- a/gdb/testsuite/gdb.base/step-over-exit.exp
> +++ b/gdb/testsuite/gdb.base/step-over-exit.exp
> @@ -91,7 +91,7 @@ delete_breakpoints
>  
> 
>  gdb_test "break marker"
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_num_re, .*" \
>      "continue to marker, first time"
>  
> 
>  # Step 2, create a breakpoint which evaluates false, and force it
> @@ -120,5 +120,5 @@ gdb_test "inferior 1" ".*Switching to inferior 1.*" \
>  # Switch back to the parent process, continue to the marker to
>  # test GDBserver's state is still correct.
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_numopt_re, .*" \
>      "continue to marker, second time"
> diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
> index 47a2a5dcb7c..fa098602c31 100644
> --- a/gdb/testsuite/gdb.cp/mb-inline.exp
> +++ b/gdb/testsuite/gdb.cp/mb-inline.exp
> @@ -46,7 +46,7 @@ gdb_test "info break" \
>      "\[\r\n\]1\.1.* y .* at .*$hdrfile:$bp_location.*\[\r\n\]1\.2.* y .* at .*$hdrfile:$bp_location.*"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo \\(i=1\\).*" \
> @@ -59,7 +59,7 @@ gdb_test "continue" \
>  gdb_test_no_output "disable 1.2" "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
>  
> 
>  gdb_test_multiple "info break" "disabled breakpoint 1.2" {
>      -re "1\.2.* n .* at .*$hdrfile:$bp_location.*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
> index 6c988e7335e..0c0d46fcb7a 100644
> --- a/gdb/testsuite/gdb.cp/mb-templates.exp
> +++ b/gdb/testsuite/gdb.cp/mb-templates.exp
> @@ -42,7 +42,7 @@ gdb_run_cmd
>  
> 
>  set test "initial condition: run to breakpoint"
>  gdb_test_multiple "" $test {
> -    -re "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
> +    -re "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
>  	pass $test
>  	break
>      }
> @@ -67,7 +67,7 @@ gdb_test_no_output {condition $bpnum i==1} \
>      "separate condition: set condition"
>      
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo<double> \\(i=1\\).*" \
> @@ -79,7 +79,7 @@ gdb_test "continue" \
>  gdb_test_no_output {disable $bpnum.1} "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
>  
> 
>  # Try disabling entire breakpoint
>  gdb_test_no_output {enable $bpnum.1} "disabling location: enable"
> diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
> index 06adf82ecbb..0ed9eae055b 100644
> --- a/gdb/testsuite/gdb.cp/ovldbreak.exp
> +++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
> @@ -380,7 +380,7 @@ gdb_test "info break" $bptable "breakpoint info (after setting on all)"
>  
> 
>  # Run through each breakpoint.
>  proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
> -    global gdb_prompt hex decimal srcfile
> +    global gdb_prompt hex decimal srcfile bkptno_num_re
>  
> 
>      if {$argument == ""} {
>          set actuals ""
> @@ -398,11 +398,11 @@ proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
>      }
>  
> 
>      gdb_test_multiple "continue" "continue to bp overloaded : $argtype" {
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              pass "continue to bp overloaded : $argtype"
>          }
>  
> 
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              if $might_kfail {
>                  kfail "c++/8130" "continue to bp overloaded : $argtype"
>              } else {
> diff --git a/gdb/testsuite/gdb.gdb/python-helper.exp b/gdb/testsuite/gdb.gdb/python-helper.exp
> index 6db8bf0df50..30eb6038f3a 100644
> --- a/gdb/testsuite/gdb.gdb/python-helper.exp
> +++ b/gdb/testsuite/gdb.gdb/python-helper.exp
> @@ -49,7 +49,7 @@ gdb_exit
>  # The main test.  This is called by the self-test framework once GDB
>  # has been started on a copy of itself.
>  proc test_python_helper {} {
> -    global py_helper_script decimal hex gdb_prompt
> +    global py_helper_script decimal hex gdb_prompt bkptno_numopt_re
>      global inferior_spawn_id
>  
> 
>      # Source the python helper script.  This script registers the
> @@ -233,7 +233,7 @@ proc test_python_helper {} {
>      # GDB stopping at the value_print breakpoint again.
>      send_inferior "ptype global_c\n"
>      gdb_test_multiple "" "hit breakpoint in outer gdb again" {
> -	-re "Breakpoint $decimal, c_print_type .*\\(outer-gdb\\) $" {
> +	-re "Breakpoint $bkptno_numopt_re, c_print_type .*\\(outer-gdb\\) $" {
>  	    pass $gdb_test_name
>  	}
>      }
> diff --git a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> index 19ccbe85e04..c080955049c 100644
> --- a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> +++ b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> @@ -69,7 +69,7 @@ if { $use_second_inferior } {
>  	"\\^running.*" \
>  	"run inferior 2"
>  
> 
> -    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\""} \
> +    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\"" "locno=\"[0-9]+\""} \
>  	"inferior i2 stops at all_threads_started"
>  
> 
>      mi_send_resuming_command "exec-continue --thread-group i2" \
> diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> index d78c96ddef1..9eec083068b 100644
> --- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> +++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> @@ -307,8 +307,13 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  	    # Consume MI event output.
>  	    with_spawn_id $mi_spawn_id {
> -		mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> -		    "$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		if { $inf == 1 } {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		} else {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} "stop at breakpoint in main"
> +		}
>  	    }
>  
> 
>  	    if { $mode == "all-stop" } {
> @@ -330,9 +335,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		    # Consume MI output.
>  		    with_spawn_id $mi_spawn_id {
> -			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			    "thread $inf.$thread stops MI"
> +			if { $inf == 1} {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +				"thread $inf.$thread stops MI"
> +			} else {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +				"thread $inf.$thread stops MI"
> +			}
>  		    }
>  		}
>  
> 
> @@ -359,9 +370,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		# Consume MI output.
>  		with_spawn_id $mi_spawn_id {
> -		    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			"thread $inf.2 stops MI"
> +		    if { $inf == 1} {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +			    "thread $inf.2 stops MI"
> +		    } else {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +			    "thread $inf.2 stops MI"
> +		    }
>  		}
>  	    }
>  	}
> @@ -434,7 +451,7 @@ proc_with_prefix test_setup { mode } {
>  
> 
>  	with_spawn_id $mi_spawn_id {
>  	    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" "$decimal" \
> -		{"" "disp=\"del\""} "main stop"
> +		{"" "disp=\"del\"" "locno=\"[0-9]+\""} "main stop"
>  	}
>  
> 
>  	# Consume CLI output.
> diff --git a/gdb/testsuite/gdb.multi/multi-arch-exec.exp b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> index a1496fb5571..dfdb746c65e 100644
> --- a/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> +++ b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> @@ -148,6 +148,7 @@ proc build_executables { first_arch } {
>  }
>  
> 
>  proc do_test { first_arch mode selected_thread } {
> +        global bkptno_numopt_re
>  	set from_exec "$first_arch-multi-arch-exec"
>  
> 
>  	clean_restart ${from_exec}
> @@ -169,7 +170,7 @@ proc do_test { first_arch mode selected_thread } {
>  
> 
>  	# Test that GDB updates the target description / arch successfuly
>  	# after the exec.
> -	gdb_test "continue" "Breakpoint 2, main.*" "continue across exec that changes architecture"
> +	gdb_test "continue" "Breakpoint $bkptno_numopt_re, main.*" "continue across exec that changes architecture"
>  }
>  
> 
>  # Test both arch1=>arch2 and arch2=>arch1.
> diff --git a/gdb/testsuite/gdb.multi/run-only-second-inf.exp b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> index fec2575f904..b94689d0bfa 100644
> --- a/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> +++ b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> @@ -46,5 +46,5 @@ gdb_load $binfile
>  if {[gdb_start_cmd] < 0} {
>      fail "start the second inf"
>  } else {
> -    gdb_test "" ".*reakpoint ., main .*${srcfile}.*" "start the second inf"
> +    gdb_test "" ".*reakpoint $bkptno_numopt_re, main .*${srcfile}.*" "start the second inf"
>  }
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> index cbccba19d12..3c079facced 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> @@ -27,7 +27,7 @@ if {[build_executable "failed to build" $testfile $srcfile {debug}]} {
>  # child.  Can be either "kill", "detach", or "exit" (to continue it to
>  # normal exit).
>  proc do_test {dispose} {
> -    global binfile
> +    global binfile bkptno_numopt_re
>  
> 
>      clean_restart $binfile
>  
> 
> @@ -77,7 +77,7 @@ proc do_test {dispose} {
>      #  Command aborted.
>      #  (gdb)
>      #
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker .*" \
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker .*" \
>  	"continue in inferior 1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi.exp b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> index e4329dca6c2..0fc1bee762f 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> @@ -84,11 +84,11 @@ if [skip_hw_watchpoint_multi_tests] {
>  	"Hardware access \\(read/write\\) watchpoint \[0-9\]+: c\r\n\r\nOld value = 0\r\nNew value = 3\r\n.*" \
>  	"catch c on inferior 2"
>  
> 
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 2"
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 2"
>  
> 
>      gdb_test "inferior 1" "witching to inferior 1 .*" "switch back to inferior 1 again"
>  
> 
>      gdb_test "continue" "Hardware access \\(read/write\\) watchpoint \[0-9\]+: b\r\n\r\nOld value = 0\r\nNew value = 2\r\n.*" "catch b on inferior 1"
>  }
>  
> 
> -gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 1"
> +gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 1"
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 402450152ac..5e4c793598e 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -227,6 +227,14 @@ set inferior_exited_re "(?:\\\[Inferior \[0-9\]+ \\(\[^\n\r\]*\\) exited)"
>  # E.g., $1, $2, etc.
>  set valnum_re "\\\$$decimal"
>  
> 
> +# A regular expression that matches a breakpoint hit with a breakpoint
> +# having several code locations.
> +set bkptno_num_re "$decimal\\.$decimal"
> +
> +# A regular expression that matches a breakpoint hit
> +# with one or several code locations.
> +set bkptno_numopt_re "($decimal\\.$decimal|$decimal)"
> +
>  ### Only procedures should come after this point.
>  
> 
>  #
> @@ -662,6 +670,7 @@ proc gdb_breakpoint { linespec args } {
>  
> 
>  proc runto { linespec args } {
>      global gdb_prompt
> +    global bkptno_numopt_re
>      global decimal
>  
> 
>      delete_breakpoints
> @@ -699,7 +708,7 @@ proc runto { linespec args } {
>  	    }
>  	    return 1
>  	}
> -	-re "Breakpoint \[0-9\]*, \[0-9xa-f\]* in .*$gdb_prompt $" { 
> +	-re "Breakpoint $bkptno_numopt_re, \[0-9xa-f\]* in .*$gdb_prompt $" {
>  	    if { $print_pass } {
>  		pass $test_name
>  	    }
> diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
> index e578a7e6f9b..ea66fdcabf8 100644
> --- a/gdb/testsuite/lib/mi-support.exp
> +++ b/gdb/testsuite/lib/mi-support.exp
> @@ -1195,11 +1195,11 @@ proc mi_detect_async {} {
>  # filename of a file without debug info.  ARGS should not include [] the
>  # list of argument is enclosed in, and other regular expressions should
>  # not include quotes.
> -# If EXTRA is a list of one element, it's the regular expression
> +# EXTRA can be a list of one, two or three elements.
> +# The first element is the regular expression
>  # for output expected right after *stopped, and before GDB prompt.
> -# If EXTRA is a list of two elements, the first element is for
> -# output right after *stopped, and the second element is output
> -# right after reason field.  The regex after reason should not include
> +# The third element is the regulation expression for the locno
> +# right after bkptno field.  The locno regex should not include
>  # the comma separating it from the following fields.
>  #
>  # When we fail to match output at all, -1 is returned.  If FILE does
> @@ -1224,7 +1224,14 @@ proc mi_expect_stop { reason func args file line extra test } {
>  
> 
>      set after_stopped ""
>      set after_reason ""
> -    if { [llength $extra] == 2 } {
> +    set locno ""
> +    if { [llength $extra] == 3 } {
> +	set after_stopped [lindex $extra 0]
> +	set after_reason [lindex $extra 1]
> +	set after_reason "${after_reason},"
> +	set locno [lindex $extra 2]
> +	set locno "${locno},"
> +    } elseif { [llength $extra] == 2 } {
>  	set after_stopped [lindex $extra 0]
>  	set after_reason [lindex $extra 1]
>  	set after_reason "${after_reason},"
> @@ -1298,10 +1305,12 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set ebn ""
>      if { $reason == "breakpoint-hit" } {
>  	set bn {bkptno="[0-9]+",}
> +	set bn "${bn}${locno}"
>      } elseif { $reason == "solib-event" } {
>  	set bn ".*"
>      } elseif { $reason == "exception-caught" } {
>  	set ebn {bkptno="[0-9]+",}
> +	set ebn "${ebn}${locno}"
>  	set bn ".*"
>  	set reason "breakpoint-hit"
>      }
> @@ -1315,6 +1324,7 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set a $after_reason
>  
> 
>      verbose -log "mi_expect_stop: expecting: \\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
> +
>      gdb_expect {
>  	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
>  	    pass "$test"



^ permalink raw reply	[flat|nested] 17+ messages in thread

* ping^10 Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-06-06  9:45 [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno Philippe Waroquiers
                   ` (9 preceding siblings ...)
  2022-08-27 14:45 ` Philippe Waroquiers
@ 2022-09-03 15:17 ` Philippe Waroquiers
  2022-11-10 15:57 ` Tom Tromey
  11 siblings, 0 replies; 17+ messages in thread
From: Philippe Waroquiers @ 2022-09-03 15:17 UTC (permalink / raw)
  To: gdb-patches

Ping ^ 10
(Eli reviewed the doc, Keith did a first code review)

It would be nice to have this reviewed at short term as GDB 13 release was planned
by Joel around early September.

Thanks
Philippe

On Mon, 2022-06-06 at 11:45 +0200, Philippe Waroquiers wrote:
> Before this patch, when a breakpoint that has multiple locations is reached,
> GDB printed:
>   Thread 1 "zeoes" hit Breakpoint 1, some_func () at somefunc1.c:5
> 
> This patch changes the message so that bkpt_print_id prints the precise
> encountered breakpoint:
>   Thread 1 "zeoes" hit Breakpoint 1.2, some_func () at somefunc1.c:5
> 
> In mi mode, bkpt_print_id also (optionally) prints a new table field "locno":
>   locno is printed when the breakpoint has more than one location.
> Note that according to the GDB user manual node 'GDB/MI Development and Front
> Ends', it is ok to add new fields without changing the MI version.
> 
> Also, when a breakpoint is reached, the convenience variables
> $bkptno and $locno are set to the encountered breakpoint number
> and location number.
> 
> $bkptno and $locno can a.o. be used in the command list of a breakpoint,
> to disable the specific encountered breakpoint, e.g.
>    disable $bkptno.$locno
> 
> In case the breakpoint has only one location, $locno is still set to
> the value 1, so as to allow a command such as:
>   disable $bkptno.$locno
> even when the breakpoint has only one location.
> 
> This also fixes a strange behaviour: when a breakpoint X has only
> one location,
>   enable|disable X.1
> is accepted but transforms the breakpoint in a multiple locations
> breakpoint having only one location.
> 
> The changes in RFA v3 handle the additional comments of Eli:
>  GDB/NEW:
>   - Use max 80-column
>   - Use 'code location' instead of 'location'.
>   - Fix typo $bkpno
>   - Ensure that disable $bkptno and disable $bkptno.$locno have
>     each their explanation inthe example
>   - Reworded the 'breakpoint-hit' paragraph.
>  gdb.texinfo:
>   - Use 'code location' instead of 'location'.
>   - Add a note to clarify the distinction between $bkptno and $bpnum.
>   - Use @kbd instead of examples with only one command.
> 
> Compared to RFA v1, the changes in v2 handle the comments given by
> Keith Seitz and Eli Zaretskii:
>   - Use %s for the result of paddress
>   - Use bkptno_numopt_re instead of 2 different -re cases
>   - use C@t{++}
>   - Add index entries for $bkptno and $locno
>   - Added an example for "locno" in the mi interface
>   - Added examples in the Break command manual.
> ---
>  gdb/NEWS                                      | 21 +++++
>  gdb/ada-lang.c                                |  2 +-
>  gdb/break-catch-syscall.c                     |  2 +-
>  gdb/break-catch-throw.c                       |  2 +-
>  gdb/breakpoint.c                              | 93 +++++++++++++++----
>  gdb/breakpoint.h                              | 14 +++
>  gdb/doc/gdb.texinfo                           | 83 ++++++++++++++++-
>  gdb/infrun.c                                  | 16 +++-
>  gdb/testsuite/gdb.ada/bp_inlined_func.exp     |  2 +-
>  gdb/testsuite/gdb.ada/operator_bp.exp         |  4 +-
>  .../gdb.base/condbreak-multi-context.exp      |  8 +-
>  gdb/testsuite/gdb.base/ctxobj.exp             | 26 ++++--
>  gdb/testsuite/gdb.base/ena-dis-br.exp         | 41 ++++----
>  gdb/testsuite/gdb.base/foll-exec-mode.exp     |  6 +-
>  gdb/testsuite/gdb.base/pie-fork.exp           |  4 +-
>  gdb/testsuite/gdb.base/step-over-exit.exp     |  4 +-
>  gdb/testsuite/gdb.cp/mb-inline.exp            |  4 +-
>  gdb/testsuite/gdb.cp/mb-templates.exp         |  6 +-
>  gdb/testsuite/gdb.cp/ovldbreak.exp            |  6 +-
>  gdb/testsuite/gdb.gdb/python-helper.exp       |  4 +-
>  .../gdb.mi/interrupt-thread-group.exp         |  2 +-
>  .../gdb.mi/user-selected-context-sync.exp     | 35 +++++--
>  gdb/testsuite/gdb.multi/multi-arch-exec.exp   |  3 +-
>  .../gdb.multi/run-only-second-inf.exp         |  2 +-
>  .../gdb.multi/watchpoint-multi-exit.exp       |  4 +-
>  gdb/testsuite/gdb.multi/watchpoint-multi.exp  |  4 +-
>  gdb/testsuite/lib/gdb.exp                     | 11 ++-
>  gdb/testsuite/lib/mi-support.exp              | 20 +++-
>  28 files changed, 335 insertions(+), 94 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 960f90b4387..a5602deee2b 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -34,6 +34,21 @@
>       whitespace from each line before using the string as the help
>       output.
>  
> 
> +* When a breakpoint with multiple code locations is hit, GDB now prints
> +  the code location using the syntax <breakpoint_number>.<location_number>
> +  such as in:
> +     Thread 1 "zeoes" hit Breakpoint 2.3, some_func () at zeoes.c:8
> +
> +* When a breakpoint is hit, GDB now sets the convenience variables $bkptno and
> +  $locno to the hit breakpoint number and code location number.
> +  This allows to disable the last hit breakpoint using
> +     (gdb) disable $bkptno
> +   or disable only the specific breakpoint code location using
> +     (gdb) disable $bkptno.$locno
> +  These commands can be used inside the command list of a breakpoint to
> +  automatically disable the just encountered breakpoint (or the just
> +  encountered specific breakpoint code location).
> +
>  * New commands
>  
> 
>  maintenance set ignore-prologue-end-flag on|off
> @@ -50,6 +65,12 @@ maintenance info line-table
>    entry corresponds to an address where a breakpoint should be placed
>    to be at the first instruction past a function's prologue.
>  
> 
> +* MI changes
> +
> + ** The async record stating the stopped reason 'breakpoint-hit' now
> +    contains an optional field locno giving the code location number
> +    when the breakpoint has multiple code locations.
> +
>  * Python API
>  
> 
>    ** New function gdb.format_address(ADDRESS, PROGSPACE, ARCHITECTURE),
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 6ab01fd27d4..bbae76f39ac 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -12348,7 +12348,7 @@ ada_catchpoint::print_it (const bpstat *bs) const
>  
> 
>    uiout->text (disposition == disp_del
>  	       ? "\nTemporary catchpoint " : "\nCatchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    /* ada_exception_name_addr relies on the selected frame being the
> diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
> index 06d48466de7..82229de33f7 100644
> --- a/gdb/break-catch-syscall.c
> +++ b/gdb/break-catch-syscall.c
> @@ -218,7 +218,7 @@ syscall_catchpoint::print_it (const bpstat *bs) const
>  						: EXEC_ASYNC_SYSCALL_RETURN));
>        uiout->field_string ("disp", bpdisp_text (b->disposition));
>      }
> -  uiout->field_signed ("bkptno", b->number);
> +  print_num_locno (bs, uiout);
>  
> 
>    if (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY)
>      uiout->text (" (call to syscall ");
> diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
> index 66cf80be1c5..5b6f5d9eca1 100644
> --- a/gdb/break-catch-throw.c
> +++ b/gdb/break-catch-throw.c
> @@ -257,7 +257,7 @@ exception_catchpoint::print_it (const bpstat *bs) const
>    bp_temp = disposition == disp_del;
>    uiout->text (bp_temp ? "Temporary catchpoint "
>  		       : "Catchpoint ");
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text ((kind == EX_EVENT_THROW ? " (exception thrown), "
>  		: (kind == EX_EVENT_CATCH ? " (exception caught), "
>  		   : " (exception rethrown), ")));
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index ed932a19ed7..c89c800f32f 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -820,6 +820,19 @@ get_breakpoint (int num)
>    return nullptr;
>  }
>  
> 
> +/* Return TRUE if NUM refer to an existing breakpoint that has
> +   multiple code locations.  */
> +
> +static bool
> +has_multiple_locations (int num)
> +{
> +  for (breakpoint *b : all_breakpoints ())
> +    if (b->number == num)
> +      return b->loc != nullptr && b->loc->next != nullptr;
> +
> +  return false;
> +}
> +
>  \f
>  
> 
>  /* Mark locations as "conditions have changed" in case the target supports
> @@ -4451,15 +4464,7 @@ bpstat_explains_signal (bpstat *bsp, enum gdb_signal sig)
>    return false;
>  }
>  
> 
> -/* Put in *NUM the breakpoint number of the first breakpoint we are
> -   stopped at.  *BSP upon return is a bpstat which points to the
> -   remaining breakpoints stopped at (but which is not guaranteed to be
> -   good for anything but further calls to bpstat_num).
> -
> -   Return 0 if passed a bpstat which does not indicate any breakpoints.
> -   Return -1 if stopped at a breakpoint that has been deleted since
> -   we set it.
> -   Return 1 otherwise.  */
> +/* See breakpoint.h.  */
>  
> 
>  int
>  bpstat_num (bpstat **bsp, int *num)
> @@ -4481,6 +4486,57 @@ bpstat_num (bpstat **bsp, int *num)
>    return 1;
>  }
>  
> 
> +/* See breakpoint.h  */
> +
> +int
> +bpstat_locno (const bpstat *bs)
> +{
> +  const struct breakpoint *b = bs->breakpoint_at;
> +  const struct bp_location *bl = bs->bp_location_at.get ();
> +
> +  int locno = 0;
> +
> +  if (b != nullptr && b->loc->next != nullptr)
> +    {
> +      const bp_location *bl_i;
> +
> +      for (bl_i = b->loc;
> +	   bl_i != bl && bl_i->next != nullptr;
> +	   bl_i = bl_i->next)
> +	locno++;
> +
> +      if (bl_i == bl)
> +	locno++;
> +      else
> +	{
> +	  warning (_("location number not found for breakpoint %d address %s."),
> +		   b->number, paddress (bl->gdbarch, bl->address));
> +	  locno = 0;
> +	}
> +    }
> +
> +  return locno;
> +}
> +
> +/* See breakpoint.h.  */
> +
> +void
> +print_num_locno (const bpstat *bs, struct ui_out *uiout)
> +{
> +  struct breakpoint *b = bs->breakpoint_at;
> +
> +  if (b == nullptr)
> +    uiout->text (_("deleted breakpoint"));
> +  else
> +    {
> +      uiout->field_signed ("bkptno", b->number);
> +
> +      int locno = bpstat_locno (bs);
> +      if (locno != 0)
> +	uiout->message (".%pF", signed_field ("locno", locno));
> +    }
> +}
> +
>  /* See breakpoint.h.  */
>  
> 
>  void
> @@ -9176,7 +9232,7 @@ ranged_breakpoint::print_it (const bpstat *bs) const
>  		      async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> -  uiout->field_signed ("bkptno", number);
> +  print_num_locno (bs, uiout);
>    uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
> @@ -11610,12 +11666,13 @@ ordinary_breakpoint::print_it (const bpstat *bs) const
>  			   async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
>        uiout->field_string ("disp", bpdisp_text (disposition));
>      }
> +
>    if (bp_temp)
> -    uiout->message ("Temporary breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Temporary breakpoint ");
>    else
> -    uiout->message ("Breakpoint %pF, ",
> -		    signed_field ("bkptno", number));
> +    uiout->text ("Breakpoint ");
> +  print_num_locno (bs, uiout);
> +  uiout->text (", ");
>  
> 
>    return PRINT_SRC_AND_LOC;
>  }
> @@ -13220,9 +13277,13 @@ enable_disable_command (const char *args, int from_tty, bool enable)
>  	  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)
> +	      && (bp_loc_range.first == 0
> +		  || (bp_loc_range.first == 1
> +		      && bp_num_range.first == bp_num_range.second
> +		      && !has_multiple_locations (bp_num_range.first))))
>  	    {
> -	      /* Handle breakpoint ids with formats 'x' or 'x-z'.  */
> +	      /* Handle breakpoint ids with formats 'x' or 'x-z'
> +		 or 'y.1' where y has only one code location.  */
>  	      map_breakpoint_number_range (bp_num_range,
>  					   enable
>  					   ? enable_breakpoint
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 566f1285e46..96d61ef5427 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -1231,6 +1231,20 @@ extern enum print_stop_action bpstat_print (bpstat *, int);
>     Return 1 otherwise.  */
>  extern int bpstat_num (bpstat **, int *);
>  
> 
> +/* If BS indicates a breakpoint and this breakpoint has several code locations,
> +   return the location number of BS, otherwise return 0.  */
> +
> +extern int bpstat_locno (const bpstat *bs);
> +
> +/* Print BS breakpoint number optionally followed by a . and breakpoint locno.
> +
> +   For a breakpoint with only one code location, outputs the signed field
> +   "bkptno" breakpoint number of BS (as returned by bpstat_num).
> +   If BS has several code locations, outputs a '.' character followed by
> +   the signed field "locno" (as returned by bpstat_locno).  */
> +
> +extern void print_num_locno (const bpstat *bs, struct ui_out *);
> +
>  /* Perform actions associated with the stopped inferior.  Actually, we
>     just use this for breakpoint commands.  Perhaps other actions will
>     go here later, but this is executed at a late time (from the
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 434add3a663..391b81f8863 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -4338,9 +4338,65 @@ are operated on.
>  @cindex latest breakpoint
>  Breakpoints are set with the @code{break} command (abbreviated
>  @code{b}).  The debugger convenience variable @samp{$bpnum} records the
> -number of the breakpoint you've set most recently; see @ref{Convenience
> -Vars,, Convenience Variables}, for a discussion of what you can do with
> -convenience variables.
> +number of the breakpoint you've set most recently:
> +@smallexample
> +(gdb) b main
> +Breakpoint 1 at 0x11c6: file zeoes.c, line 24.
> +(gdb) p $bpnum
> +$1 = 1
> +@end smallexample
> +
> +A breakpoint may be mapped to multiple code locations for example with
> +inlined functions, Ada generics, C@t{++} templates or overloaded function names.
> +@value{GDBN} then indicates the number of code locations in the breakpoint
> +command output:
> +@smallexample
> +(gdb) b some_func
> +Breakpoint 2 at 0x1179: some_func. (3 locations)
> +(gdb) p $bpnum
> +$2 = 2
> +(gdb)
> +@end smallexample
> +
> +@vindex $bkptno@r{, convenience variable}
> +@vindex $locno@r{, convenience variable}
> +When your program stops on a breakpoint, the convenience variables
> +@samp{$bkptno} and @samp{$locno} are respectively set to the number of
> +the encountered breakpoint and the number of the breakpoint's code location:
> +@smallexample
> +Thread 1 "zeoes" hit Breakpoint 2.1, some_func () at zeoes.c:8
> +8	  printf("some func\n");
> +(gdb) p $bkptno
> +$5 = 2
> +(gdb) p $locno
> +$6 = 1
> +(gdb)
> +@end smallexample
> +
> +Note that @samp{$bkptno} and @samp{$bpnum} are not equivalent:
> +@samp{$bkptno} is set to the breakpoint number @b{last hit}, while
> +@samp{$bpnum} is set to the breakpoint number @b{last set}.
> +
> +
> +If the encountered breakpoint has only one code location, @samp{$locno} is set
> +to 1:
> +@smallexample
> +Breakpoint 1, main (argc=1, argv=0x7fffffffe018) at zeoes.c:24
> +24	  if (argc > 1)
> +(gdb) p $bkptno
> +$3 = 1
> +(gdb) p $locno
> +$4 = 1
> +(gdb)
> +@end smallexample
> +
> +The @samp{$bkptno} and @samp{$locno} variables can typically be used
> +in a breakpoint command list.
> +(@pxref{Break Commands, ,Breakpoint Command Lists}). For example, as
> +part of the breakpoint command list, you can disable completely the
> +encountered breakpoint using @samp{disable $bkptno} or disable the
> +specific encountered breakpoint location using @samp{disable
> +$bkptno.$locno}.
>  
> 
>  @table @code
>  @item break @var{locspec}
> @@ -5739,6 +5795,13 @@ Expressions}).
>  Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
>  disabled within a @var{command-list}.
>  
> 
> +Inside a command list, you can use the command
> +@kbd{disable $bkptno} to disable the encountered breakpoint.
> +
> +If your breakpoint has several code locations, the command
> +@kbd{disable $bkptno.$locno} will disable the specific breakpoint code
> +location encountered.
> +
>  You can use breakpoint commands to start your program up again.  Simply
>  use the @code{continue} command, or @code{step}, or any other command
>  that resumes execution.
> @@ -32570,6 +32633,20 @@ line="13",arch="i386:x86_64"@}
>  (gdb)
>  @end smallexample
>  
> 
> +For a @samp{breakpoint-hit} stopped reason, when the breakpoint
> +encountered has multiple locations, the field @samp{bkptno} is
> +followed by the field @samp{locno}.
> +
> +@smallexample
> +-exec-continue
> +^running
> +(gdb)
> +@@Hello world
> +*stopped,reason="breakpoint-hit",disp="keep",bkptno="2",locno="3",frame=@{
> +func="foo",args=[],file="hello.c",fullname="/home/foo/bar/hello.c",
> +line="13",arch="i386:x86_64"@}
> +(gdb)
> +@end smallexample
>  
> 
>  @subheading The @code{-exec-finish} Command
>  @findex -exec-finish
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 02c98b50c8c..e5ad062a914 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -8494,7 +8494,21 @@ print_stop_location (const target_waitstatus &ws)
>       LOCATION: Print only location
>       SRC_AND_LOC: Print location and source line.  */
>    if (do_frame_printing)
> -    print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    {
> +      if (tp->control.stop_bpstat != nullptr)
> +	{
> +	  const struct breakpoint *b = tp->control.stop_bpstat->breakpoint_at;
> +
> +	  if (b != nullptr)
> +	    {
> +	      int locno = bpstat_locno (tp->control.stop_bpstat);
> +	      set_internalvar_integer (lookup_internalvar ("bkptno"), b->number);
> +	      set_internalvar_integer (lookup_internalvar ("locno"),
> +				       (locno > 0 ? locno : 1));
> +	    }
> +	}
> +      print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> +    }
>  }
>  
> 
>  /* See infrun.h.  */
> diff --git a/gdb/testsuite/gdb.ada/bp_inlined_func.exp b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> index 076e8c2425f..3f94c163819 100644
> --- a/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> +++ b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
> @@ -42,7 +42,7 @@ gdb_test "break read_small" \
>  for {set i 0} {$i < 4} {incr i} {
>      with_test_prefix "iteration $i" {
>  	gdb_test "continue" \
> -	    "Breakpoint $decimal, b\\.read_small \\(\\).*" \
> +	    "Breakpoint $bkptno_num_re, b\\.read_small \\(\\).*" \
>  	    "stopped in read_small"
>      }
>  }
> diff --git a/gdb/testsuite/gdb.ada/operator_bp.exp b/gdb/testsuite/gdb.ada/operator_bp.exp
> index 655e7af479f..e3928419ed6 100644
> --- a/gdb/testsuite/gdb.ada/operator_bp.exp
> +++ b/gdb/testsuite/gdb.ada/operator_bp.exp
> @@ -56,7 +56,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to \"$op\""
>  }
>  
> 
> @@ -86,7 +86,7 @@ foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&"
>  foreach op { "+" "-" "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
>      set op_re [string_to_regexp $op]
>      gdb_test "continue" \
> -             "Breakpoint $decimal, ops\\.\"$op_re\" .*"\
> +             "Breakpoint $bkptno_numopt_re, ops\\.\"$op_re\" .*"\
>               "continue to ops.\"$op\""
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> index b540df973a3..742315178e3 100644
> --- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> +++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
> @@ -140,11 +140,11 @@ with_test_prefix "scenario 1" {
>      gdb_run_cmd
>  
> 
>      # Check our conditional breakpoints.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> @@ -208,11 +208,11 @@ with_test_prefix "scenario 2" {
>      gdb_run_cmd
>  
> 
>      # Check that we hit enabled locations only.
> -    gdb_test "" ".*Breakpoint \[0-9\]+, A::func .*" \
> +    gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \
>  	"run until A::func"
>      gdb_test "print a" " = 10"
>  
> 
> -    gdb_test "continue" "Continuing.*Breakpoint \[0-9\]+, C::func .*" \
> +    gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \
>  	"run until C::func"
>      gdb_test "print c" " = 30"
>  
> 
> diff --git a/gdb/testsuite/gdb.base/ctxobj.exp b/gdb/testsuite/gdb.base/ctxobj.exp
> index 9c010f54d79..0b589a7d6e6 100644
> --- a/gdb/testsuite/gdb.base/ctxobj.exp
> +++ b/gdb/testsuite/gdb.base/ctxobj.exp
> @@ -67,9 +67,16 @@ gdb_test "break ctxobj-f.c:$bp_location" \
>           "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
>           "break in get_version functions"
>  
> 
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_1 \\(\\).*" \
> -         "continue to get_version_1"
> +global expect_out
> +set test "continue to get_version_1"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_1 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  # Try printing "this_version_num".  There are two global variables
>  # with that name, and some systems such as GNU/Linux merge them
> @@ -100,10 +107,15 @@ gdb_test "print this_version_num == v" \
>          "print libctxobj1's this_version_num from symtab"
>  
> 
>  # Do the same, but from get_version_2.
> -
> -gdb_test "continue" \
> -         "Breakpoint $decimal, get_version_2 \\(\\).*" \
> -         "continue to get_version_2"
> +set test "continue to get_version_2"
> +gdb_test_multiple "continue" $test {
> +    -re "Breakpoint ($bkptno_num_re), get_version_2 \\(\\).*" {
> +	set bpno $expect_out(1,string)
> +	pass $test
> +    }
> +}
> +# Verify the $bkptno.$locno convenience variables are set to the hit bpno.
> +gdb_test "printf \"%d.%d\\n\", \$bkptno, \$locno" "$bpno" "$test \$bkptno.\$locno is $bpno"
>  
> 
>  gdb_test "print this_version_num == v" \
>           " = 1" \
> diff --git a/gdb/testsuite/gdb.base/ena-dis-br.exp b/gdb/testsuite/gdb.base/ena-dis-br.exp
> index 24925cf7185..04b3f134b44 100644
> --- a/gdb/testsuite/gdb.base/ena-dis-br.exp
> +++ b/gdb/testsuite/gdb.base/ena-dis-br.exp
> @@ -67,14 +67,21 @@ gdb_test "info break $bp" \
>  # See the comments in condbreak.exp for "run until breakpoint at
>  # marker1" for an explanation of the xfail below.
>  set test "continue to break marker1"
> +set bpno 0
>  gdb_test_multiple "continue" "$test" {
> -    -re "Breakpoint \[0-9\]*, marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	pass "$test"
>      }
> -    -re "Breakpoint \[0-9\]*, $hex in marker1.*$gdb_prompt $" {
> +    -re "Breakpoint (\[0-9\]*), $hex in marker1.*$gdb_prompt $" {
> +	set bpno $expect_out(1,string)
>  	xfail "$test"
>      }
>  }
> +# Verify the $bkptno convenience variable is equal to the hit bpno.
> +gdb_test "print \$bkptno" " = $bpno" "$test \$bkptno is $bpno"
> +# Verify the $locno is 1, as there is only one code location.
> +gdb_test "print \$locno" " = 1" "$test \$locno is 1"
>  
> 
>  gdb_test_no_output "delete $bp" "delete break marker1"
>  
> 
> @@ -359,7 +366,8 @@ with_test_prefix "4th breakpoint" {
>  }
>  
> 
>  # Perform tests for disable/enable commands on multiple
> -# locations and breakpoints.
> +# code locations and breakpoints.  If a breakpoint has only one code location,
> +# enable/disable num  and enable/disable num.1 should be equivalent.
>  #
>  # WHAT - the command to test (disable/enable).
>  #
> @@ -372,7 +380,7 @@ proc test_ena_dis_br { what } {
>      global b3
>      global b4
>      global gdb_prompt
> -    
> +
>      # OPPOS    - the command opposite to WHAT.
>      # WHAT_RES - whether breakpoints are expected to end
>      #            up enabled or disabled.
> @@ -395,13 +403,13 @@ proc test_ena_dis_br { what } {
>  	set p2 "pass"
>      }
>  
> 
> -    # Now enable(disable) $b.1 $b2.1.
> +    # Now enable(disable) $b1.1 $b2.1.
>      gdb_test_no_output "$what $b1.1 $b2.1" "$what \$b1.1 \$b2.1"
>      set test1 "${what}d \$b1.1 and \$b2.1"
>  
> 
>      # Now $b1.1 and $b2.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -       -re "(${b1}.1)(\[^\n\r\]*)( n.*)(${b2}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +       -re "(${b1})(\[^\n\r\]*)( n.*)(${b2})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> @@ -420,19 +428,16 @@ proc test_ena_dis_br { what } {
>         "${what}d \$b1"
>  
> 
>      gdb_test_no_output "$oppos $b3" "$oppos \$b3"
> +    # Now $b4 $b3 should be enabled(disabled)
> +    set test1 "${what}d \$b4 and \$b3"
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $oppos_res.*).*(${b4})(\[^\n\r\]*)( $oppos_res.*)" "$test1"
> +
>      gdb_test_no_output "$what $b4 $b3.1" "$what \$b4 \$b3.1"
> -    set test1 "${what}d \$b4 and \$b3.1,remain ${oppos}d \$b3"
> +    set test1 "${what}d \$b4 and \$b3.1, changing \$b3"
> +
> +    # Now $b4 $b3 should be enabled(disabled)
> +    gdb_test "info break" "(${b3})(\[^\n\r]*)( $what_res.*).*(${b4})(\[^\n\r\]*)( $what_res.*)" "$test1"
>  
> 
> -    # Now $b4 $b3.1 should be enabled(disabled) and
> -    # $b3 should remain disabled(enabled).
> -    gdb_test_multiple "info break" "$test1" {
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b3}.1)(\[^\n\r\]*)( n.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p1 "$test1"
> -       }
> -       -re "(${b3})(\[^\n\r]*)( $oppos_res.*)(${b4})(\[^\n\r\]*)( $what_res.*)$gdb_prompt $" {
> -           $p2 "$test1"
> -       }
> -    }
>  
> 
>      # Now enable(disable) '$b4.1 fooobaar'.  This should error on
>      # fooobaar.
> @@ -443,7 +448,7 @@ proc test_ena_dis_br { what } {
>  
> 
>      # $b4.1 should be enabled(disabled).
>      gdb_test_multiple "info break" "$test1" {
> -        -re "(${b4}.1)(\[^\n\r\]*)( n.*)$gdb_prompt $" {
> +        -re "(${b4})(\[^\n\r\]*)( n.*)$gdb_prompt $" {
>             $p1 "$test1"
>         }
>         -re ".*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.base/foll-exec-mode.exp b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> index 918f3e4fd5f..cb6d975a767 100644
> --- a/gdb/testsuite/gdb.base/foll-exec-mode.exp
> +++ b/gdb/testsuite/gdb.base/foll-exec-mode.exp
> @@ -99,7 +99,7 @@ proc do_catch_exec_test { } {
>  # before re-running.
>  
> 
>  proc do_follow_exec_mode_tests { mode cmd infswitch } {
> -    global binfile srcfile srcfile2 testfile testfile2
> +    global binfile srcfile srcfile2 testfile testfile2 bkptno_numopt_re
>      global gdb_prompt
>  
> 
>      with_test_prefix "$mode,$cmd,$infswitch" {
> @@ -125,7 +125,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  	# Set up the output we expect to see after we execute past the exec.
>  	#
>  	set execd_line [gdb_get_line_number "after-exec" $srcfile2]
> -	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint .,.*${srcfile2}:${execd_line}.*$gdb_prompt $"
> +	set expected_re ".*xecuting new program: .*${testfile2}.*Breakpoint ${bkptno_numopt_re},.*${srcfile2}:${execd_line}.*$gdb_prompt $"
>  
> 
>  	# Set a breakpoint after the exec call if we aren't single-stepping
>  	# past it.
> @@ -189,7 +189,7 @@ proc do_follow_exec_mode_tests { mode cmd infswitch } {
>  		send_gdb "y\n"
>  		exp_continue
>  	    }
> -	    -re "Starting program: .*$expected_inf.*Breakpoint .,.*\r\n$gdb_prompt $" {
> +	    -re "Starting program: .*$expected_inf.*Breakpoint $bkptno_numopt_re,.*\r\n$gdb_prompt $" {
>  		pass $test
>  	    }
>  	}
> diff --git a/gdb/testsuite/gdb.base/pie-fork.exp b/gdb/testsuite/gdb.base/pie-fork.exp
> index efc357d39a2..19e9d3a5537 100644
> --- a/gdb/testsuite/gdb.base/pie-fork.exp
> +++ b/gdb/testsuite/gdb.base/pie-fork.exp
> @@ -54,10 +54,10 @@ proc_with_prefix test_detach_on_fork_follow_child {} {
>  proc_with_prefix test_no_detach_on_fork {} {
>      setup_test "off"
>  
> 
> -    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 1.1 .* hit Breakpoint 2.1, break_here.*" \
>  	     "continue from thread 1.1"
>      gdb_test "thread 2.1"
> -    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2, break_here.*" \
> +    gdb_test "continue" "\r\nThread 2.1 .* hit Breakpoint 2.2, break_here.*" \
>  	     "continue from thread 2.1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.base/step-over-exit.exp b/gdb/testsuite/gdb.base/step-over-exit.exp
> index f8bd99980fe..575319c564c 100644
> --- a/gdb/testsuite/gdb.base/step-over-exit.exp
> +++ b/gdb/testsuite/gdb.base/step-over-exit.exp
> @@ -91,7 +91,7 @@ delete_breakpoints
>  
> 
>  gdb_test "break marker"
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_num_re, .*" \
>      "continue to marker, first time"
>  
> 
>  # Step 2, create a breakpoint which evaluates false, and force it
> @@ -120,5 +120,5 @@ gdb_test "inferior 1" ".*Switching to inferior 1.*" \
>  # Switch back to the parent process, continue to the marker to
>  # test GDBserver's state is still correct.
>  
> 
> -gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \
> +gdb_test "continue" "Continuing\\..*Breakpoint $bkptno_numopt_re, .*" \
>      "continue to marker, second time"
> diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
> index 47a2a5dcb7c..fa098602c31 100644
> --- a/gdb/testsuite/gdb.cp/mb-inline.exp
> +++ b/gdb/testsuite/gdb.cp/mb-inline.exp
> @@ -46,7 +46,7 @@ gdb_test "info break" \
>      "\[\r\n\]1\.1.* y .* at .*$hdrfile:$bp_location.*\[\r\n\]1\.2.* y .* at .*$hdrfile:$bp_location.*"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo \\(i=1\\).*" \
> @@ -59,7 +59,7 @@ gdb_test "continue" \
>  gdb_test_no_output "disable 1.2" "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo \\(i=0\\).*" "disabling location: run to breakpoint"
>  
> 
>  gdb_test_multiple "info break" "disabled breakpoint 1.2" {
>      -re "1\.2.* n .* at .*$hdrfile:$bp_location.*$gdb_prompt $" {
> diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
> index 6c988e7335e..0c0d46fcb7a 100644
> --- a/gdb/testsuite/gdb.cp/mb-templates.exp
> +++ b/gdb/testsuite/gdb.cp/mb-templates.exp
> @@ -42,7 +42,7 @@ gdb_run_cmd
>  
> 
>  set test "initial condition: run to breakpoint"
>  gdb_test_multiple "" $test {
> -    -re "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
> +    -re "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*$gdb_prompt $" {
>  	pass $test
>  	break
>      }
> @@ -67,7 +67,7 @@ gdb_test_no_output {condition $bpnum i==1} \
>      "separate condition: set condition"
>      
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<int> \\(i=1\\).*" "separate condition: run to breakpoint"
>  
> 
>  gdb_test "continue" \
>      ".*Breakpoint.*foo<double> \\(i=1\\).*" \
> @@ -79,7 +79,7 @@ gdb_test "continue" \
>  gdb_test_no_output {disable $bpnum.1} "disabling location: disable"
>  
> 
>  gdb_run_cmd
> -gdb_test "" "Breakpoint \[0-9\]+,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
> +gdb_test "" "Breakpoint $bkptno_num_re,.*foo<double> \\(i=1\\).*" "disabling location: run to breakpoint"
>  
> 
>  # Try disabling entire breakpoint
>  gdb_test_no_output {enable $bpnum.1} "disabling location: enable"
> diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
> index 06adf82ecbb..0ed9eae055b 100644
> --- a/gdb/testsuite/gdb.cp/ovldbreak.exp
> +++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
> @@ -380,7 +380,7 @@ gdb_test "info break" $bptable "breakpoint info (after setting on all)"
>  
> 
>  # Run through each breakpoint.
>  proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
> -    global gdb_prompt hex decimal srcfile
> +    global gdb_prompt hex decimal srcfile bkptno_num_re
>  
> 
>      if {$argument == ""} {
>          set actuals ""
> @@ -398,11 +398,11 @@ proc continue_to_bp_overloaded {bpnumber might_fail line argtype argument} {
>      }
>  
> 
>      gdb_test_multiple "continue" "continue to bp overloaded : $argtype" {
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}(, )?$actuals\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              pass "continue to bp overloaded : $argtype"
>          }
>  
> 
> -        -re "Continuing.\r\n\r\nBreakpoint $bpnumber, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
> +        -re "Continuing.\r\n\r\nBreakpoint $bkptno_num_re, foo::overload1arg \\(this=${hex}, arg=.*\\) at .*$srcfile:$line\r\n$decimal\[\t \]+{ $body }.*$gdb_prompt $" {
>              if $might_kfail {
>                  kfail "c++/8130" "continue to bp overloaded : $argtype"
>              } else {
> diff --git a/gdb/testsuite/gdb.gdb/python-helper.exp b/gdb/testsuite/gdb.gdb/python-helper.exp
> index 6db8bf0df50..30eb6038f3a 100644
> --- a/gdb/testsuite/gdb.gdb/python-helper.exp
> +++ b/gdb/testsuite/gdb.gdb/python-helper.exp
> @@ -49,7 +49,7 @@ gdb_exit
>  # The main test.  This is called by the self-test framework once GDB
>  # has been started on a copy of itself.
>  proc test_python_helper {} {
> -    global py_helper_script decimal hex gdb_prompt
> +    global py_helper_script decimal hex gdb_prompt bkptno_numopt_re
>      global inferior_spawn_id
>  
> 
>      # Source the python helper script.  This script registers the
> @@ -233,7 +233,7 @@ proc test_python_helper {} {
>      # GDB stopping at the value_print breakpoint again.
>      send_inferior "ptype global_c\n"
>      gdb_test_multiple "" "hit breakpoint in outer gdb again" {
> -	-re "Breakpoint $decimal, c_print_type .*\\(outer-gdb\\) $" {
> +	-re "Breakpoint $bkptno_numopt_re, c_print_type .*\\(outer-gdb\\) $" {
>  	    pass $gdb_test_name
>  	}
>      }
> diff --git a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> index 19ccbe85e04..c080955049c 100644
> --- a/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> +++ b/gdb/testsuite/gdb.mi/interrupt-thread-group.exp
> @@ -69,7 +69,7 @@ if { $use_second_inferior } {
>  	"\\^running.*" \
>  	"run inferior 2"
>  
> 
> -    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\""} \
> +    mi_expect_stop "breakpoint-hit" "all_threads_started" ".*" ".*" ".*" {"" "disp=\"keep\"" "locno=\"[0-9]+\""} \
>  	"inferior i2 stops at all_threads_started"
>  
> 
>      mi_send_resuming_command "exec-continue --thread-group i2" \
> diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> index d78c96ddef1..9eec083068b 100644
> --- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> +++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> @@ -307,8 +307,13 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  	    # Consume MI event output.
>  	    with_spawn_id $mi_spawn_id {
> -		mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> -		    "$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		if { $inf == 1 } {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\""} "stop at breakpoint in main"
> +		} else {
> +		    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \
> +			"$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} "stop at breakpoint in main"
> +		}
>  	    }
>  
> 
>  	    if { $mode == "all-stop" } {
> @@ -330,9 +335,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		    # Consume MI output.
>  		    with_spawn_id $mi_spawn_id {
> -			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			    "thread $inf.$thread stops MI"
> +			if { $inf == 1} {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +				"thread $inf.$thread stops MI"
> +			} else {
> +			    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +				"" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +				"thread $inf.$thread stops MI"
> +			}
>  		    }
>  		}
>  
> 
> @@ -359,9 +370,15 @@ proc test_continue_to_start { mode inf } {
>  
> 
>  		# Consume MI output.
>  		with_spawn_id $mi_spawn_id {
> -		    mi_expect_stop "breakpoint-hit" "child_sub_function" \
> -			"" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> -			"thread $inf.2 stops MI"
> +		    if { $inf == 1} {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
> +			    "thread $inf.2 stops MI"
> +		    } else {
> +			mi_expect_stop "breakpoint-hit" "child_sub_function" \
> +			    "" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
> +			    "thread $inf.2 stops MI"
> +		    }
>  		}
>  	    }
>  	}
> @@ -434,7 +451,7 @@ proc_with_prefix test_setup { mode } {
>  
> 
>  	with_spawn_id $mi_spawn_id {
>  	    mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" "$decimal" \
> -		{"" "disp=\"del\""} "main stop"
> +		{"" "disp=\"del\"" "locno=\"[0-9]+\""} "main stop"
>  	}
>  
> 
>  	# Consume CLI output.
> diff --git a/gdb/testsuite/gdb.multi/multi-arch-exec.exp b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> index a1496fb5571..dfdb746c65e 100644
> --- a/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> +++ b/gdb/testsuite/gdb.multi/multi-arch-exec.exp
> @@ -148,6 +148,7 @@ proc build_executables { first_arch } {
>  }
>  
> 
>  proc do_test { first_arch mode selected_thread } {
> +        global bkptno_numopt_re
>  	set from_exec "$first_arch-multi-arch-exec"
>  
> 
>  	clean_restart ${from_exec}
> @@ -169,7 +170,7 @@ proc do_test { first_arch mode selected_thread } {
>  
> 
>  	# Test that GDB updates the target description / arch successfuly
>  	# after the exec.
> -	gdb_test "continue" "Breakpoint 2, main.*" "continue across exec that changes architecture"
> +	gdb_test "continue" "Breakpoint $bkptno_numopt_re, main.*" "continue across exec that changes architecture"
>  }
>  
> 
>  # Test both arch1=>arch2 and arch2=>arch1.
> diff --git a/gdb/testsuite/gdb.multi/run-only-second-inf.exp b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> index fec2575f904..b94689d0bfa 100644
> --- a/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> +++ b/gdb/testsuite/gdb.multi/run-only-second-inf.exp
> @@ -46,5 +46,5 @@ gdb_load $binfile
>  if {[gdb_start_cmd] < 0} {
>      fail "start the second inf"
>  } else {
> -    gdb_test "" ".*reakpoint ., main .*${srcfile}.*" "start the second inf"
> +    gdb_test "" ".*reakpoint $bkptno_numopt_re, main .*${srcfile}.*" "start the second inf"
>  }
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> index cbccba19d12..3c079facced 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp
> @@ -27,7 +27,7 @@ if {[build_executable "failed to build" $testfile $srcfile {debug}]} {
>  # child.  Can be either "kill", "detach", or "exit" (to continue it to
>  # normal exit).
>  proc do_test {dispose} {
> -    global binfile
> +    global binfile bkptno_numopt_re
>  
> 
>      clean_restart $binfile
>  
> 
> @@ -77,7 +77,7 @@ proc do_test {dispose} {
>      #  Command aborted.
>      #  (gdb)
>      #
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker .*" \
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker .*" \
>  	"continue in inferior 1"
>  }
>  
> 
> diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi.exp b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> index e4329dca6c2..0fc1bee762f 100644
> --- a/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> +++ b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
> @@ -84,11 +84,11 @@ if [skip_hw_watchpoint_multi_tests] {
>  	"Hardware access \\(read/write\\) watchpoint \[0-9\]+: c\r\n\r\nOld value = 0\r\nNew value = 3\r\n.*" \
>  	"catch c on inferior 2"
>  
> 
> -    gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 2"
> +    gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 2"
>  
> 
>      gdb_test "inferior 1" "witching to inferior 1 .*" "switch back to inferior 1 again"
>  
> 
>      gdb_test "continue" "Hardware access \\(read/write\\) watchpoint \[0-9\]+: b\r\n\r\nOld value = 0\r\nNew value = 2\r\n.*" "catch b on inferior 1"
>  }
>  
> 
> -gdb_test "continue" "Breakpoint \[0-9\]+, marker_exit .*" "catch marker_exit in inferior 1"
> +gdb_test "continue" "Breakpoint $bkptno_numopt_re, marker_exit .*" "catch marker_exit in inferior 1"
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 402450152ac..5e4c793598e 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -227,6 +227,14 @@ set inferior_exited_re "(?:\\\[Inferior \[0-9\]+ \\(\[^\n\r\]*\\) exited)"
>  # E.g., $1, $2, etc.
>  set valnum_re "\\\$$decimal"
>  
> 
> +# A regular expression that matches a breakpoint hit with a breakpoint
> +# having several code locations.
> +set bkptno_num_re "$decimal\\.$decimal"
> +
> +# A regular expression that matches a breakpoint hit
> +# with one or several code locations.
> +set bkptno_numopt_re "($decimal\\.$decimal|$decimal)"
> +
>  ### Only procedures should come after this point.
>  
> 
>  #
> @@ -662,6 +670,7 @@ proc gdb_breakpoint { linespec args } {
>  
> 
>  proc runto { linespec args } {
>      global gdb_prompt
> +    global bkptno_numopt_re
>      global decimal
>  
> 
>      delete_breakpoints
> @@ -699,7 +708,7 @@ proc runto { linespec args } {
>  	    }
>  	    return 1
>  	}
> -	-re "Breakpoint \[0-9\]*, \[0-9xa-f\]* in .*$gdb_prompt $" { 
> +	-re "Breakpoint $bkptno_numopt_re, \[0-9xa-f\]* in .*$gdb_prompt $" {
>  	    if { $print_pass } {
>  		pass $test_name
>  	    }
> diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
> index e578a7e6f9b..ea66fdcabf8 100644
> --- a/gdb/testsuite/lib/mi-support.exp
> +++ b/gdb/testsuite/lib/mi-support.exp
> @@ -1195,11 +1195,11 @@ proc mi_detect_async {} {
>  # filename of a file without debug info.  ARGS should not include [] the
>  # list of argument is enclosed in, and other regular expressions should
>  # not include quotes.
> -# If EXTRA is a list of one element, it's the regular expression
> +# EXTRA can be a list of one, two or three elements.
> +# The first element is the regular expression
>  # for output expected right after *stopped, and before GDB prompt.
> -# If EXTRA is a list of two elements, the first element is for
> -# output right after *stopped, and the second element is output
> -# right after reason field.  The regex after reason should not include
> +# The third element is the regulation expression for the locno
> +# right after bkptno field.  The locno regex should not include
>  # the comma separating it from the following fields.
>  #
>  # When we fail to match output at all, -1 is returned.  If FILE does
> @@ -1224,7 +1224,14 @@ proc mi_expect_stop { reason func args file line extra test } {
>  
> 
>      set after_stopped ""
>      set after_reason ""
> -    if { [llength $extra] == 2 } {
> +    set locno ""
> +    if { [llength $extra] == 3 } {
> +	set after_stopped [lindex $extra 0]
> +	set after_reason [lindex $extra 1]
> +	set after_reason "${after_reason},"
> +	set locno [lindex $extra 2]
> +	set locno "${locno},"
> +    } elseif { [llength $extra] == 2 } {
>  	set after_stopped [lindex $extra 0]
>  	set after_reason [lindex $extra 1]
>  	set after_reason "${after_reason},"
> @@ -1298,10 +1305,12 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set ebn ""
>      if { $reason == "breakpoint-hit" } {
>  	set bn {bkptno="[0-9]+",}
> +	set bn "${bn}${locno}"
>      } elseif { $reason == "solib-event" } {
>  	set bn ".*"
>      } elseif { $reason == "exception-caught" } {
>  	set ebn {bkptno="[0-9]+",}
> +	set ebn "${ebn}${locno}"
>  	set bn ".*"
>  	set reason "breakpoint-hit"
>      }
> @@ -1315,6 +1324,7 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set a $after_reason
>  
> 
>      verbose -log "mi_expect_stop: expecting: \\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
> +
>      gdb_expect {
>  	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
>  	    pass "$test"



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-06-06  9:45 [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno Philippe Waroquiers
                   ` (10 preceding siblings ...)
  2022-09-03 15:17 ` ping^10 " Philippe Waroquiers
@ 2022-11-10 15:57 ` Tom Tromey
  2022-11-12 16:15   ` Philippe Waroquiers
  11 siblings, 1 reply; 17+ messages in thread
From: Tom Tromey @ 2022-11-10 15:57 UTC (permalink / raw)
  To: Philippe Waroquiers via Gdb-patches; +Cc: Philippe Waroquiers

>>>>> "Philippe" == Philippe Waroquiers via Gdb-patches <gdb-patches@sourceware.org> writes:

Hi.  Thanks for the patch.  I'm sorry about the long delay on the
review.  I'm not really sure what to do about it but I think we need to
make some change here, because too many patches are falling into this
"10 pings" hole.

Philippe> Before this patch, when a breakpoint that has multiple locations is reached,
Philippe> GDB printed:
Philippe>   Thread 1 "zeoes" hit Breakpoint 1, some_func () at somefunc1.c:5

Philippe> This patch changes the message so that bkpt_print_id prints the precise
Philippe> encountered breakpoint:
Philippe>   Thread 1 "zeoes" hit Breakpoint 1.2, some_func () at somefunc1.c:5

Philippe> In mi mode, bkpt_print_id also (optionally) prints a new table field "locno":
Philippe>   locno is printed when the breakpoint has more than one location.
Philippe> Note that according to the GDB user manual node 'GDB/MI Development and Front
Philippe> Ends', it is ok to add new fields without changing the MI version.

I think the idea as a whole is sound, thank you for tackling this.

Philippe> Also, when a breakpoint is reached, the convenience variables
Philippe> $bkptno and $locno are set to the encountered breakpoint number
Philippe> and location number.

I believe we have a convention that new internally-created convenience
variables will start with "_".

I wondered a little whether we wanted to introduce $_bkptno or just
repurpose the already-existing $bpnum, but I see we already do this kind
of thing for tracepoints, and I suppose having different variables for
different semantics is good... it's just a bit unfortunate that the
names are similar.

Note that the breakpoint number convenience variable is
https://sourceware.org/bugzilla/show_bug.cgi?id=12464, so this should
be in a Bug: trailer and also mentioned in the form "PR breakpoints/12464"
somewhere in the commit message.

Philippe> +Inside a command list, you can use the command
Philippe> +@kbd{disable $bkptno} to disable the encountered breakpoint.
Philippe> +
Philippe> +If your breakpoint has several code locations, the command
Philippe> +@kbd{disable $bkptno.$locno} will disable the specific breakpoint code
Philippe> +location encountered.

It may be worth mentioning that the $_bkptno.$_locno form will work even
when your breakpoint only has a single location, and also the ".1"
special case for single-location breakpoints.

Philippe> @@ -8494,7 +8494,21 @@ print_stop_location (const target_waitstatus &ws)
Philippe>       LOCATION: Print only location
Philippe>       SRC_AND_LOC: Print location and source line.  */
Philippe>    if (do_frame_printing)
Philippe> -    print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
Philippe> +    {
Philippe> +      if (tp->control.stop_bpstat != nullptr)
Philippe> +	{
Philippe> +	  const struct breakpoint *b = tp->control.stop_bpstat->breakpoint_at;
Philippe> +
Philippe> +	  if (b != nullptr)
Philippe> +	    {
Philippe> +	      int locno = bpstat_locno (tp->control.stop_bpstat);
Philippe> +	      set_internalvar_integer (lookup_internalvar ("bkptno"), b->number);
Philippe> +	      set_internalvar_integer (lookup_internalvar ("locno"),
Philippe> +				       (locno > 0 ? locno : 1));

This is in print_stop_location - but what if the location is not
printed?

I am curious if these variables can be, are intended to be, or should be
usable from breakpoint conditions or silent 'commands'.

I suspect maybe bpstat_do_actions_1 is a better spot for this, though
I'm not really sure.

Tom

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno.
  2022-11-10 15:57 ` Tom Tromey
@ 2022-11-12 16:15   ` Philippe Waroquiers
  0 siblings, 0 replies; 17+ messages in thread
From: Philippe Waroquiers @ 2022-11-12 16:15 UTC (permalink / raw)
  To: Tom Tromey, Philippe Waroquiers via Gdb-patches

On Thu, 2022-11-10 at 08:57 -0700, Tom Tromey wrote:
> > > > > > "Philippe" == Philippe Waroquiers via Gdb-patches <gdb-patches@sourceware.org>
> > > > > > writes:


> Philippe> Also, when a breakpoint is reached, the convenience variables
> Philippe> $bkptno and $locno are set to the encountered breakpoint number
> Philippe> and location number.
> 
> I believe we have a convention that new internally-created convenience
> variables will start with "_".
> 
> I wondered a little whether we wanted to introduce $_bkptno or just
> repurpose the already-existing $bpnum, but I see we already do this kind
> of thing for tracepoints, and I suppose having different variables for
> different semantics is good... it's just a bit unfortunate that the
> names are similar.
Re-using $bpnum was discarded as this would break existing scripts assuming
$bpnum value is kept unchanged when a break is hit.

Thinking again about the names, having $bpnum and $bkptno (or $_bkptno)
is confusing.
So, $_hit_bpnum and $_hit_locno for the 2 new variables seem more clear
and more consistent.

> 
> Note that the breakpoint number convenience variable is
> https://sourceware.org/bugzilla/show_bug.cgi?id=12464, so this should
> be in a Bug: trailer and also mentioned in the form "PR breakpoints/12464"
> somewhere in the commit message.
> 
> Philippe> +Inside a command list, you can use the command
> Philippe> +@kbd{disable $bkptno} to disable the encountered breakpoint.
> Philippe> +
> Philippe> +If your breakpoint has several code locations, the command
> Philippe> +@kbd{disable $bkptno.$locno} will disable the specific breakpoint code
> Philippe> +location encountered.
> 
> It may be worth mentioning that the $_bkptno.$_locno form will work even
> when your breakpoint only has a single location, and also the ".1"
> special case for single-location breakpoints.
Will do.

> 
> Philippe> @@ -8494,7 +8494,21 @@ print_stop_location (const target_waitstatus &ws)
> Philippe>       LOCATION: Print only location
> Philippe>       SRC_AND_LOC: Print location and source line.  */
> Philippe>    if (do_frame_printing)
> Philippe> -    print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
> Philippe> +    {
> Philippe> +      if (tp->control.stop_bpstat != nullptr)
> Philippe> +	{
> Philippe> +	  const struct breakpoint *b = tp->control.stop_bpstat->breakpoint_at;
> Philippe> +
> Philippe> +	  if (b != nullptr)
> Philippe> +	    {
> Philippe> +	      int locno = bpstat_locno (tp->control.stop_bpstat);
> Philippe> +	      set_internalvar_integer (lookup_internalvar ("bkptno"), b-
> >number);
> Philippe> +	      set_internalvar_integer (lookup_internalvar ("locno"),
> Philippe> +				       (locno > 0 ? locno : 1));
> 
> This is in print_stop_location - but what if the location is not
> printed?
> 
> I am curious if these variables can be, are intended to be, or should be
> usable from breakpoint conditions or silent 'commands'.

I think the semantic we want for these variables is to give
the breakpoint number of the breakpoint that was just (or last) hit.

I did not know about the "silent" breakpoint feature.
IMO, it looks better to have these variables set for silent breakpoints
as they should be available in the silent breakpoint command list.

A condition evaluating to false means the breakpoint is not considered as hit
(e.g. the nr of times a breakpoint is hit is only incremented
and its commands are only run when the condition is true).

Also, for some targets, the breakpoint condition are evaluated
at the target side.

So, it looks reasonable to me to only set these variables when a breakpoint is (really)
hit, and not to set them when evaluating a breakpoint condition.

> 
> I suspect maybe bpstat_do_actions_1 is a better spot for this, though
> I'm not really sure.
Effectively not very clear, in particular, when several breakpoints are set
at the same place and when some or all of these breakpoints are silent.
When several breakpoints are not silent, GDB prints only one of these.
In this case, the variables should be set to the printed breakpoint.
When all breakpoints are silent, I guess it is not important to choose
a particular value.

Waiting for a possible reply to this mail, I will start a new version
of the patch based on the above


Thanks
Philippe

 



^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2022-11-12 16:15 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-06  9:45 [RFAv3] Show locno for 'multi location' breakpoint hit msg+conv var $bkptno $locno Philippe Waroquiers
2022-06-06 10:53 ` Eli Zaretskii
2022-06-13 17:51 ` Philippe Waroquiers
2022-06-14 17:32   ` Keith Seitz
2022-06-14 17:41     ` Eli Zaretskii
2022-06-14 21:27       ` Philippe Waroquiers
2022-06-19 17:46 ` Philippe Waroquiers
2022-06-26 17:27 ` Philippe Waroquiers
2022-07-22 16:57 ` Philippe Waroquiers
2022-07-29 18:56 ` Philippe Waroquiers
2022-08-08  6:52 ` Philippe Waroquiers
2022-08-14 14:08 ` Philippe Waroquiers
2022-08-21 12:05 ` Philippe Waroquiers
2022-08-27 14:45 ` Philippe Waroquiers
2022-09-03 15:17 ` ping^10 " Philippe Waroquiers
2022-11-10 15:57 ` Tom Tromey
2022-11-12 16:15   ` Philippe Waroquiers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).