Skip to content

Commit 944b1b1

Browse files
committed
gdb: fix display of thread condition for multi-location breakpoints
This commit addresses the issue in PR gdb/30087. If a breakpoint with multiple locations has a thread condition, then the 'info breakpoints' output is a little messed up, here's an example of the current output: (gdb) break foo thread 1 Breakpoint 2 at 0x401114: foo. (3 locations) (gdb) break bar thread 1 Breakpoint 3 at 0x40110a: file /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c, line 32. (gdb) info breakpoints Num Type Disp Enb Address What 2 breakpoint keep y <MULTIPLE> thread 1 stop only in thread 1 2.1 y 0x0000000000401114 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 2.2 y 0x0000000000401146 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 2.3 y 0x0000000000401168 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 3 breakpoint keep y 0x000000000040110a in bar at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:32 thread 1 stop only in thread 1 Notice that, at the end of the location for breakpoint 3, the 'thread 1' condition is printed, but this is then repeated on the next line with 'stop only in thread 1'. In contrast, for breakpoint 2, the 'thread 1' appears randomly, in the "What" column, though slightly offset, non of the separate locations have the 'thread 1' information. Additionally for breakpoint 2 we also get a 'stop only in thread 1' line. There's two things going on here. First the randomly placed 'thread 1' for breakpoint 2 is due to a bug in print_one_breakpoint_location, where we check the variable part_of_multiple instead of header_of_multiple. If I fix this oversight, then the output is now: (gdb) break foo thread 1 Breakpoint 2 at 0x401114: foo. (3 locations) (gdb) break bar thread 1 Breakpoint 3 at 0x40110a: file /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c, line 32. (gdb) info breakpoints Num Type Disp Enb Address What 2 breakpoint keep y <MULTIPLE> stop only in thread 1 2.1 y 0x0000000000401114 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 thread 1 2.2 y 0x0000000000401146 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 thread 1 2.3 y 0x0000000000401168 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 thread 1 3 breakpoint keep y 0x000000000040110a in bar at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:32 thread 1 stop only in thread 1 The 'thread 1' condition is now displayed at the end of each location, which makes the output the same for single location breakpoints and multi-location breakpoints. However, there's still some duplication here. Both breakpoints 2 and 3 include a 'stop only in thread 1' line, and it feels like the additional 'thread 1' is redundant. In fact, there's a comment to this very effect in the code: /* FIXME: This seems to be redundant and lost here; see the "stop only in" line a little further down. */ So, lets fix this FIXME. The new plan is to remove all the trailing 'thread 1' markers from the CLI output, we now get this: (gdb) break foo thread 1 Breakpoint 2 at 0x401114: foo. (3 locations) (gdb) break bar thread 1 Breakpoint 3 at 0x40110a: file /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c, line 32. (gdb) info breakpoints Num Type Disp Enb Address What 2 breakpoint keep y <MULTIPLE> stop only in thread 1 2.1 y 0x0000000000401114 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 2.2 y 0x0000000000401146 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 2.3 y 0x0000000000401168 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 3 breakpoint keep y 0x000000000040110a in bar at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:32 stop only in thread 1 All of the above points are also true for the Ada 'task' breakpoint condition, and the changes I've made also update how the task information is printed, though in the case of the Ada task there was no 'stop only in task XXX' line printed, so I've added one of those. Obviously it can't be quite that easy. For MI backwards compatibility I've retained the existing code (but now only for MI like outputs), which ensures we should generate backwards compatible output. I've extended an Ada test to cover the new task related output, and updated all the tests I could find that checked for the old output. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30087 Approved-By: Pedro Alves <[email protected]>
1 parent 3a8be57 commit 944b1b1

File tree

5 files changed

+136
-22
lines changed

5 files changed

+136
-22
lines changed

gdb/breakpoint.c

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6468,20 +6468,19 @@ print_one_breakpoint_location (struct breakpoint *b,
64686468
output_thread_groups (uiout, "thread-groups", inf_nums, mi_only);
64696469
}
64706470

6471-
if (!part_of_multiple)
6471+
/* In the MI output, each location of a thread or task specific
6472+
breakpoint includes the relevant thread or task ID. This is done for
6473+
backwards compatibility reasons.
6474+
6475+
For the CLI output, the thread/task information is printed on a
6476+
separate line, see the 'stop only in thread' and 'stop only in task'
6477+
output below. */
6478+
if (!header_of_multiple && uiout->is_mi_like_p ())
64726479
{
64736480
if (b->thread != -1)
6474-
{
6475-
/* FIXME: This seems to be redundant and lost here; see the
6476-
"stop only in" line a little further down. */
6477-
uiout->text (" thread ");
6478-
uiout->field_signed ("thread", b->thread);
6479-
}
6481+
uiout->field_signed ("thread", b->thread);
64806482
else if (b->task != 0)
6481-
{
6482-
uiout->text (" task ");
6483-
uiout->field_signed ("task", b->task);
6484-
}
6483+
uiout->field_signed ("task", b->task);
64856484
}
64866485

64876486
uiout->text ("\n");
@@ -6536,7 +6535,14 @@ print_one_breakpoint_location (struct breakpoint *b,
65366535
}
65376536
uiout->text ("\n");
65386537
}
6539-
6538+
6539+
if (!part_of_multiple && b->task != 0)
6540+
{
6541+
uiout->text ("\tstop only in task ");
6542+
uiout->field_signed ("task", b->task);
6543+
uiout->text ("\n");
6544+
}
6545+
65406546
if (!part_of_multiple)
65416547
{
65426548
if (b->hit_count)

gdb/testsuite/gdb.ada/tasks.exp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,21 +50,18 @@ gdb_test "watch j task 1 task 3" "You can specify only one task\\."
5050
# breakpoint in the list that matched the triggered-breakpoint's
5151
# address, no matter which task it was specific to.
5252
gdb_test "break break_me task 1" "Breakpoint .* at .*"
53+
gdb_test "info breakpoints" "foo.adb:${decimal}\r\n\\s+stop only in task 1" \
54+
"check info breakpoints for task 1 breakpoint"
5355

5456
# Now, insert a breakpoint that should stop only if task 3 stops, and
5557
# extract its number.
56-
set bp_number -1
57-
set test "break break_me task 3"
58-
gdb_test_multiple $test $test {
59-
-re "Breakpoint (.*) at .*$gdb_prompt $" {
60-
set bp_number $expect_out(1,string)
61-
pass $test
62-
}
63-
}
64-
58+
gdb_breakpoint "break_me task 3" message
59+
set bp_number [get_integer_valueof "\$bpnum" -1]
6560
if {$bp_number < 0} {
6661
return
6762
}
63+
gdb_test "info breakpoints" "foo.adb:${decimal}\r\n\\s+stop only in task 3" \
64+
"check info breakpoints for task 3 breakpoint"
6865

6966
# Continue to that breakpoint. Task 2 should hit it first, and GDB
7067
# is expected to ignore that hit and resume the execution. Only then

gdb/testsuite/gdb.base/save-bp.exp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ gdb_test_sequence "info break" "info break" [list \
7979
"\[\r\n\]+Num +Type +Disp +Enb +Address +What" \
8080
"\[\r\n\]+$bp_row_start break_me at \[^\r\n\]*$srcfile:\[0-9\]+" \
8181
"\[\r\n\]+$bp_row_start main at \[^\r\n\]*$srcfile:$loc_bp2" \
82-
"\[\r\n\]+$bp_row_start main at \[^\r\n\]*$srcfile:$loc_bp3 +thread 1" \
82+
"\[\r\n\]+$bp_row_start main at \[^\r\n\]*$srcfile:$loc_bp3" \
8383
"\[\r\n\]+\[ \t]+stop only in thread 1" \
8484
"\[\r\n\]+$bp_row_start main at \[^\r\n\]*$srcfile:$loc_bp4" \
8585
"\[\r\n\]+\[ \t\]+stop only if i == 1( \\((host|target) evals\\))?" \
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/* This testcase is part of GDB, the GNU debugger.
2+
3+
Copyright 2022-2023 Free Software Foundation, Inc.
4+
5+
This program is free software; you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation; either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <http://www.gnu.org/licenses/>. */
17+
18+
volatile int global_var = 0;
19+
20+
__attribute__((__always_inline__)) static inline void
21+
foo (void)
22+
{
23+
int i;
24+
25+
for (i = 0; i < 10; ++i)
26+
global_var = i;
27+
}
28+
29+
static void
30+
bar (void)
31+
{
32+
global_var = 0;
33+
foo ();
34+
}
35+
36+
int
37+
main (void)
38+
{
39+
global_var = 0;
40+
foo ();
41+
bar ();
42+
foo ();
43+
return 0;
44+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Copyright 2022-2023 Free Software Foundation, Inc.
2+
3+
# This program is free software; you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License as published by
5+
# the Free Software Foundation; either version 3 of the License, or
6+
# (at your option) any later version.
7+
#
8+
# This program is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
# GNU General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU General Public License
14+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
16+
# Create a multi-location breakpoint with a thread condition, then check the
17+
# output of 'info breakpoints' to ensure that the thread condition is
18+
# displayed correctly.
19+
20+
standard_testfile
21+
22+
if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } {
23+
return -1
24+
}
25+
26+
if {![runto_main]} {
27+
return -1
28+
}
29+
30+
delete_breakpoints
31+
32+
gdb_breakpoint "foo thread 1"
33+
set bp_number [get_integer_valueof "\$bpnum" 0]
34+
if { $bp_number == 0 } {
35+
unresolved "breakpoint not placed correctly"
36+
return -1
37+
}
38+
39+
set saw_header false
40+
set saw_cond false
41+
set loc_count 0
42+
gdb_test_multiple "info breakpoints" \
43+
"check thread condition is displayed correctly" {
44+
-re "\r\nNum\\s+\[^\r\n\]+\r\n" {
45+
exp_continue
46+
}
47+
48+
-re "^$bp_number\\s+breakpoint\\s+keep\\s+y\\s+<MULTIPLE>\\s*\r\n" {
49+
set saw_header true
50+
exp_continue
51+
}
52+
53+
-re "^\\s+stop only in thread 1\r\n" {
54+
set saw_cond true
55+
exp_continue
56+
}
57+
58+
-re "^$bp_number\\.\[123\]\\s+\[^\r\n\]+:${decimal}\r\n" {
59+
incr loc_count
60+
exp_continue
61+
}
62+
63+
-re "^$gdb_prompt $" {
64+
gdb_assert { $saw_header && $saw_cond && $loc_count == 3} \
65+
$gdb_test_name
66+
}
67+
}

0 commit comments

Comments
 (0)