@@ -3,6 +3,11 @@
*** Changes since GDB 15
+* Printing multiple breakpoint locations when setting a breakpoint
+
+ Setting a breakpoint that is instantiated for multiple locations now prints
+ locations limited by "set max-breakpoint-location-printed <count>".
+
* Debugging support for Intel MPX has been removed. This includes the
removal of
** MPX register support
@@ -170,6 +170,19 @@ static bool bl_address_is_meaningful (bp_location *loc);
static int find_loc_num_by_location (const bp_location *loc);
+/* Maximum number of locations printed when setting a breakpoint. Controlled
+ by "set max-breakpoint-locations-printed <number>". */
+
+static unsigned int breakpoint_show_max_locations = 10;
+static void
+show_max_breakpoint_location_printed (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ gdb_printf (file,
+ _("Number of breakpoint location printed is %s.\n"),
+ value);
+}
+
/* update_global_location_list's modes of operation wrt to whether to
insert locations now. */
enum ugll_insert_mode
@@ -11785,38 +11798,85 @@ code_breakpoint::say_where () const
}
else
{
- const bp_location &bl = this->first_loc ();
- if (opts.addressprint || bl.symtab == nullptr)
- gdb_printf (" at %ps",
- styled_string (address_style.style (),
- paddress (bl.gdbarch,
- bl.address)));
- if (bl.symtab != NULL)
- {
- /* If there is a single location, we can print the location
- more nicely. */
- if (!this->has_multiple_locations ())
+ if (this->has_multiple_locations ())
+ {
+ int n = std::distance (m_locations.begin (), m_locations.end ());
+
+ gdb_printf (" for %s at %d locations:\n", locspec->to_string (), n);
+ int loc_idx = 0;
+ for (const bp_location &bl : m_locations)
+ {
+ gdb_printf (" Location %u", loc_idx + 1);
+ if (opts.addressprint || bl.symtab == nullptr)
+ gdb_printf (
+ " at %ps",
+ styled_string (address_style.style (),
+ paddress (bl.gdbarch, bl.address)));
+
+ if (bl.symtab != nullptr)
+ {
+ const struct symbol *sym = bl.symbol;
+ if (sym)
+ gdb_printf (
+ " in function %ps",
+ styled_string (function_name_style.style (),
+ sym->print_name ()));
+
+ const char *filename
+ = symtab_to_filename_for_display (bl.symtab);
+ gdb_printf (
+ " in file %ps, line %d",
+ styled_string (file_name_style.style (), filename),
+ bl.line_number);
+ }
+
+ if (all_inferiors ().size () > 1)
+ {
+ for (const auto &inf : all_inferiors ())
+ if (inf->pspace == bl.pspace)
+ gdb_printf (" on inferior %d", inf->num);
+ }
+ else if (bl.owner->inferior != -1)
+ gdb_printf (" on inferior %d", bl.owner->inferior);
+
+ loc_idx++;
+
+ gdb_printf (".");
+ if (loc_idx < n)
+ gdb_printf ("\n");
+
+ /* The user (or default) has selected a maximum number of
+ locations to be printed. */
+ if (loc_idx >= breakpoint_show_max_locations)
+ break;
+ }
+
+ /* We printed less locations than there are present, let the user
+ know how many more there are. */
+ if (loc_idx < n)
{
- const char *filename
- = symtab_to_filename_for_display (bl.symtab);
- gdb_printf (": file %ps, line %d.",
- styled_string (file_name_style.style (),
- filename),
- bl.line_number);
+ int omitted_locs = n - loc_idx;
+ gdb_printf ("%u additional location%s not printed.",
+ omitted_locs, omitted_locs > 1 ? "s" : "");
}
- else
- /* This is not ideal, but each location may have a
- different file name, and this at least reflects the
- real situation somewhat. */
- gdb_printf (": %s.", locspec->to_string ());
}
-
- if (this->has_multiple_locations ())
+ else
{
- int n = std::distance (m_locations.begin (), m_locations.end ());
- gdb_printf (" (%d locations)", n);
+ const bp_location &bl = this->first_loc ();
+ if (opts.addressprint || bl.symtab == nullptr)
+ gdb_printf (" at %ps",
+ styled_string (address_style.style (),
+ paddress (bl.gdbarch, bl.address)));
+ if (bl.symtab != nullptr)
+ {
+ const char *filename
+ = symtab_to_filename_for_display (bl.symtab);
+ gdb_printf (": file %ps, line %d.",
+ styled_string (file_name_style.style (), filename),
+ bl.line_number);
+ }
}
- }
+ }
}
/* See breakpoint.h. */
@@ -15245,6 +15305,17 @@ Usage: agent-printf \"format string\", ARG1, ARG2, ARG3, ..., ARGN\n\
This supports most C printf format specifications, like %s, %d, etc.\n\
This is useful for formatted output in user-defined commands."));
+ add_setshow_uinteger_cmd ("max-breakpoint-locations-printed", class_support,
+ &breakpoint_show_max_locations,_("\
+Set number of locations printed when setting a breakpoint."), _("\
+Show number of locations printed when setting a breakpoint."), _("\
+Use this to choose how many number of locations are printed\n\
+when setting a breakpoint.\n\
+A value of \"unlimited\", or zero, means there's no limit."),
+ nullptr, /* set_cmd */
+ show_max_breakpoint_location_printed,
+ &setlist, &showlist);
+
automatic_hardware_breakpoints = true;
gdb::observers::about_to_proceed.attach (breakpoint_about_to_proceed,
@@ -4518,16 +4518,47 @@ $1 = 1
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
+@value{GDBN} then lists the number of code locations in the breakpoint
command output:
@smallexample
(gdb) b some_func
-Breakpoint 2 at 0x1179: some_func. (3 locations)
+Breakpoint 2 for some_func at 3 locations:
+ Location 1 at 0x118e in function some_func in file somefunc.cc, line 23.
+ Location 2 at 0x11ee in function some_func in file somefunc.cc, line 38.
+ Location 3 at 0x12fe in function some_func in file someother.cc, line 58.
(gdb) p $bpnum
$2 = 2
(gdb)
@end smallexample
+@cindex @code{break}, how many locations are displayed
+By default, @value{GDBN} prints up to ten breakpoint locations, you can change
+this using @code{set max-breakpoint-locations-printed}:
+
+@smallexample
+(gdb) set max-breakpoint-locations-printed 2
+(gdb) b some_func
+Breakpoint 2 for some_func at 3 locations:
+ Location 1 at 0x118e in function some_func in file somefunc.cc, line 23.
+ Location 2 at 0x11ee in function some_func in file somefunc.cc, line 38.
+1 additional location not printed.
+(gdb)
+@end smallexample
+
+@table @code
+@kindex set max-breakpoint-locations-printed
+@item set max-breakpoint-locations-printed @var{count}
+@itemx set max-breakpoint-locations-printed unlimited
+Make the @code{break} command display up to @var{count} locations.
+Setting @var{count} to @code{unlimited} or 0 means there's no limit.
+
+@kindex show max-breakpoint-locations-printed
+@item show max-breakpoint-locations-printed
+Display the number of locations that @code{break} will print. If the number
+of locations is greater than the limit, the additional number of locations
+will be listed.
+@end table
+
@vindex $_hit_bpnum@r{, convenience variable}
@vindex $_hit_locno@r{, convenience variable}
When your program stops on a breakpoint, the convenience variables
@@ -4637,7 +4668,10 @@ warning: failed to validate condition at location 0x11ce, disabling:
No symbol "a" in current context.
warning: failed to validate condition at location 0x11b6, disabling:
No symbol "a" in current context.
-Breakpoint 1 at 0x11b6: func. (3 locations)
+Breakpoint 1 for func at 3 locations:
+ Location 1 at 0x11ce in function func in file somefunc.cc, line 23.
+ Location 2 at 0x11b6 in function func in file somefunc.cc, line 38.
+ Location 3 at 0x12fe in function func in file someother.cc, line 58.
@end smallexample
Locations that are disabled because of the condition are denoted by an
@@ -4681,7 +4715,10 @@ warning: failed to validate condition at location 2, disabling:
No symbol "foo" in current context.
warning: failed to validate condition at location 3, disabling:
No symbol "foo" in current context.
-Breakpoint 1 at 0x1158: test.c:18. (3 locations)
+Breakpoint 1 for func at 3 locations:
+ Location 1 at 0x1158 in function func in file test.c, line 18.
+ Location 2 at 0x11b6 in function func in file test.c, line 28.
+ Location 3 at 0x12fe in function func in file test.c, line 58.
@end smallexample
This causes all the present locations where the breakpoint would
@@ -61,9 +61,7 @@ if ![runto_main] {
}
set bp_location [gdb_get_line_number "STOP" "ctxobj-f.c"]
-gdb_test "break ctxobj-f.c:$bp_location" \
- "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
- "break in get_version functions"
+gdb_breakpoint "ctxobj-f.c:$bp_location"
global expect_out
set test "continue to get_version_1"
@@ -90,7 +90,7 @@ proc do_test { action1 action2 } {
if { $action2 == "start" } {
gdb_test "start" "Temporary breakpoint $::decimal\(?:\.$::decimal\)?, main .*"
} elseif { $action2 == "run" } {
- gdb_test "break main" "Breakpoint $::decimal at $::hex.*"
+ gdb_breakpoint "main"
gdb_test "run" "Breakpoint $::decimal\(?:\.$::decimal\)?, main .*"
} elseif { $action2 == "attach" } {
set test_spawn_id [spawn_wait_for_attach $::binfile]
@@ -332,6 +332,8 @@ gdb_test "info breakpoints" "No breakpoints, watchpoints, tracepoints, or catchp
# Test choice "all".
# This is copy-and-paste from set_bp_overloaded.
+gdb_test_no_output "set max-breakpoint-locations-printed 0"
+
incr bpnum
send_gdb "break foo::overload1arg\n"
gdb_expect {
@@ -340,7 +342,7 @@ gdb_expect {
# Choose all.
send_gdb "1\n"
gdb_expect {
- -re "Breakpoint $bpnum at $hex: foo::overload1arg. .12 locations.\r\n.*$gdb_prompt $" {
+ -re "[gdb_multi_loc_regex Breakpoint 12]$gdb_prompt $" {
pass "set bp on overload1arg all"
}
-re ".*$gdb_prompt $" {
@@ -1397,4 +1397,6 @@ proc test_driver {} {
if-expression
}
+gdb_test_no_output "set max-breakpoint-locations-printed 0"
+
test_driver
@@ -69,7 +69,7 @@ if { [is_remote host] } {
send_gdb "\n"
gdb_test "" \
- "Breakpoint $decimal at $hex: thefile.cc:twodup\\(\\). \[(\]2 locations\[)\]" \
+ "[gdb_multi_loc_regex Breakpoint 2]\[^\r\n\]*" \
"set break at unique function name in two source files"
}
}
new file mode 100644
@@ -0,0 +1,41 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2024 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+template <typename T>
+int
+templ1 (T param)
+{
+ return (int) param; /* Break here. */
+}
+
+template <>
+int
+templ1 (char* param)
+{
+ return 2;
+}
+
+int
+main ()
+{
+ templ1 (1L);
+ templ1 (1.0f);
+ templ1 (1U);
+ templ1 (1UL);
+ templ1 (1ULL);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,56 @@
+# Copyright 2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Tests of printing of multiple breakpoint locations when setting a breakpoint.
+
+standard_testfile .cc
+
+require allow_cplus_tests
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile]} {
+ return -1
+}
+
+gdb_test_no_output "set confirm off"
+
+gdb_test_no_output "set multiple-symbols all"
+
+set bp_location [gdb_get_line_number "Break here." $srcfile]
+gdb_breakpoint "$bp_location" -locs 5
+
+delete_breakpoints
+
+gdb_test_no_output "set max-breakpoint-locations-printed 2"
+
+set bp_location [gdb_get_line_number "Break here." $srcfile]
+
+gdb_breakpoint $bp_location -locs 5 -add_locs 3
+
+delete_breakpoints
+
+set bp_location [gdb_get_line_number "Break here." $srcfile]
+
+gdb_breakpoint "$bp_location inferior 1" -locs 5 -add_locs 3 -inferior 1
+
+delete_breakpoints
+
+# Now add the 2nd inferior.
+gdb_test "add-inferior" "Added inferior 2.*" "add inferior 2"
+gdb_test "inferior 2" "Switching to inferior 2.*" "switch to inferior 2"
+gdb_file_cmd $binfile
+
+gdb_test_no_output "set max-breakpoint-locations-printed 20"
+
+gdb_breakpoint "$bp_location" -locs 10 -inferior "\[12\]"
@@ -69,7 +69,9 @@ proc do_test { mi_version use_fix_flag expect_fixed_output } {
set pattern [make_breakpoints_pattern $expect_fixed_output 2 y y]
mi_gdb_test "break a_very_unique_name" \
[multi_line "&\"break a_very_unique_name\\\\n\"" \
- "~\"Breakpoint ${decimal} at.*\\(2 locations\\)\\\\n\"" \
+ "~\"Breakpoint ${decimal} for.*at.*2 locations:\\\\n\"" \
+ "~\" Location ${decimal}.*\\\\n\"" \
+ "~\" Location ${decimal}.*\\\\n\"" \
"=breakpoint-created,${pattern}" \
"\\^done" ] \
"break a_very_unique_name"
@@ -293,9 +293,7 @@ proc test_continue_to_start { mode inf } {
with_spawn_id $gdb_main_spawn_id {
# Continue to the point where we know for sure the threads are
# started.
- gdb_test "tbreak $srcfile:$main_break_line" \
- "Temporary breakpoint ${any}" \
- "set breakpoint in main"
+ gdb_breakpoint "$srcfile:$main_break_line" {temporary}
gdb_continue_to_breakpoint "main breakpoint"
@@ -321,9 +319,7 @@ proc test_continue_to_start { mode inf } {
foreach thread { 2 3 } {
gdb_test "thread $inf.$thread" ".*" "select child thread $inf.$thread"
- gdb_test "tbreak $srcfile:$thread_loop_line" \
- "Temporary breakpoint ${any}" \
- "set breakpoint for thread $inf.$thread"
+ gdb_breakpoint "$srcfile:$thread_loop_line" {temporary}
gdb_continue_to_breakpoint "continue thread $inf.$thread to infinite loop breakpoint"
@@ -347,12 +343,8 @@ proc test_continue_to_start { mode inf } {
# Put a thread-specific breakpoint for thread 2 of the current
# inferior. We don't put a breakpoint for thread 3, since we
# want to let it run.
- set test "set thread-specific breakpoint, thread $inf.2"
- gdb_test_multiple "tbreak $srcfile:$thread_loop_line thread $inf.2" $test {
- -re "Temporary breakpoint ${any}\r\n$gdb_prompt " {
- pass $test
- }
- }
+ gdb_breakpoint "$srcfile:$thread_loop_line thread $inf.2" \
+ {temporary}
# Confirm the stop of thread $inf.2.
set test "thread $inf.2 stops CLI"
@@ -105,7 +105,7 @@ proc check_info_breakpoints { testname bp_number expected_loc_count } {
# Create an inferior-specific breakpoint. Use gdb_test instead of
# gdb_breakpoint here as we want to check the breakpoint was placed in
# multiple locations.
-gdb_breakpoint "foo inferior 1" -locs 2
+gdb_breakpoint "foo inferior 1" -locs 2 -inferior 1
set bp_number [get_integer_valueof "\$bpnum" "INVALID" \
"get b/p number for inferior specific breakpoint"]
@@ -29,8 +29,7 @@ proc test_continue {non-stop} {
}
proc set_break {inf} {
- gdb_test "break function${inf} thread ${inf}.1" \
- "Breakpoint ${::decimal} at ${::hex}: file .*, line ${::decimal}\\."
+ gdb_breakpoint "function${inf} thread ${inf}.1"
}
# Select inferior INF, and then run to a breakpoint on inferior
@@ -51,13 +51,11 @@ proc test_ping_pong_next {} {
gdb_test "thread 1.1" "Switching to thread 1.1 .*"
- gdb_test "break $srcfile:$line1 thread 1.1" \
- "Breakpoint .*$srcfile, line $line1\\."
+ gdb_breakpoint "$srcfile:$line1 thread 1.1"
gdb_test "continue" "hit Breakpoint .*"
- gdb_test "break $srcfile:$line2 thread 2.1" \
- "Breakpoint .*$srcfile, line $line2\\."
+ gdb_breakpoint "$srcfile:$line2 thread 2.1"
# Now block inferior 1 and issue "next". We should stop at the
# breakpoint for inferior 2, given schedlock off.
@@ -765,7 +765,7 @@ proc_with_prefix test_bkpt_qualified {} {
clean_restart ${testfile}
set one_location_re "Breakpoint $decimal at $hex:.*line $decimal."
- set two_location_re "Breakpoint $decimal at $hex:.*2 locations."
+ set two_location_re "[gdb_multi_loc_regex Breakpoint 2]\[^\r\n\]*"
if {![runto_main]} {
return 0
@@ -417,6 +417,9 @@ proc completion::_create_bp {break_command} {
-re "\\\(\($decimal\) locations\\\)\r\n$gdb_prompt $" {
set found_locations "$expect_out(1,string)"
}
+ -re "[gdb_multi_loc_regex Breakpoint \[0-9\]+]$gdb_prompt $" {
+ set found_locations 1
+ }
-re "Breakpoint $decimal at $hex: file .*, line .*$gdb_prompt $" {
set found_locations 1
}
@@ -668,15 +668,30 @@ proc gdb_starti_cmd { {inferior_args {}} } {
return -1
}
+# Construct a breakpoint regex for multiple bp locations given a breakpoint
+# command BREAK_MESSAGE and a regex of expected locations LOCS.
+# This is useful for constructing multiple location regex where the
+# gdb_breakpoint proc cannot be used (for instance in completion tests).
+# It is also used in proc gdb_breakpoint.
+
+proc gdb_multi_loc_regex { break_message locs { inferior ""}} {
+ return [multi_line \
+ "$break_message \[0-9\]+ for \[^\r\n\]+ at\[^\r\n\]* $locs locations:" \
+ "(?: Location $::decimal at $::hex\[^\r\n\]*$inferior\.\\r\n)+" ]
+}
+
# Set a breakpoint using LINESPEC.
#
# If there is an additional argument it is a list of options; the supported
# options are allow-pending, temporary, message, no-message and qualified.
# For multiple breakpoint locations additional options are used. These
-# are -locs and -extra:
+# are -locs, -extra, -add_locs and -inferior:
# -locs specifies how many locations to expect the breakpoint set output
# and enforces that a single location match is an error.
# -extra allows specifying extra matches that need to appear in the output.
+# -add_locs specifies a regex for additional locations printed.
+# -inferior specifies a regex for "on inferior" output locations are in
+# different inferiors.
#
# The result is 1 for success, 0 for failure.
#
@@ -692,6 +707,7 @@ proc gdb_breakpoint { linespec args } {
parse_some_args {
{locs "\[0-9\]+"}
+ {add_locs ""}
{extra "<nomatch>"}
{inferior ""}
}
@@ -734,6 +750,19 @@ proc gdb_breakpoint { linespec args } {
set test_name "gdb_breakpoint: set breakpoint at $linespec"
+ # If requested, expect "on inferior" in the locations output.
+ if { $inferior != ""} {
+ set inferior "on inferior $inferior"
+ }
+
+ set multiloc_msg [gdb_multi_loc_regex $break_message $locs $inferior]
+
+ set additional_locs ""
+ if { $add_locs != "" } {
+ set additional_locs \
+ "$add_locs additional location\[s\]* not printed\.\r\n"
+ }
+
# The extra regex is setup to not match unless the caller specifies
# an extra match.
gdb_test_multiple "$break_command $linespec" $test_name {
@@ -747,7 +776,7 @@ proc gdb_breakpoint { linespec args } {
-re "$break_message \[0-9\]*: file .*, line $decimal.\r\n$gdb_prompt $" {
incr single_loc
}
- -re "$break_message \[0-9\]+ at .*\($locs locations\).*\r\n$gdb_prompt $" {
+ -re "$multiloc_msg$additional_locs$gdb_prompt $" {
incr multiple_locs
}
-re "$break_message \[0-9\]+ at .*\.\r\n$gdb_prompt $" {