From: Markus Metzger <markus.t.metzger@intel.com>
To: gdb-patches@sourceware.org
Cc: Guinevere Larsen <guinevere@redhat.com>
Subject: [RFC PATCH 1/8] gdb, infrun: do not discard a step-completed pending waitstatus
Date: Thu, 1 Oct 2026 12:28:40 +0200 [thread overview]
Message-ID: <20261001102847.576880-2-markus.t.metzger@intel.com> (raw)
In-Reply-To: <20261001102847.576880-1-markus.t.metzger@intel.com>
Consider a scenario with two breakpoints on adjacent instructions:
bp1 at 0xf00
bp2 at 0xf01
as well as two threads in all-stop-on-top-of-non-stop mode.
Assume that threads A hits bp1 and we report the breakpoint hit to the
user. When the user continues, we start a step-over for thread A at 0xf00.
Assume that thread B now hits bp1 and we report the breakpoint hit to the
user. We stop all threads to report the event. Meanwhile, the step-over
of thread A completes, so we save the pending waitstatus (stop_pc=0xf01,
currently_stepping=1) of thread A.
When the user continues, clear_proceed_status_thread() discards the
pending step completed waitstatus of thread A, and proceed() starts
another step-over for thread A at 0xf01.
We skip bp2 for thread A.
Remove the code in clear_proceed_status_thread() that discards a step
completed waitstatus and let it get handled normally. This involves
calling finish_step_over() to clean up displaced stepping state.
This introduces an additional step completed stop event for thread A that
results in two user-visible changes in behavior when switching to thread A
and resuming that thread:
- stepi/nexti completes without making progress
- adding a breakpoint at the current location before resuming hits that
breakpoint
Fixes gdb/34380.
Tested-By: Guinevere Larsen <guinevere@redhat.com>
---
gdb/infrun.c | 25 ++-----
gdb/testsuite/gdb.threads/adjacent-bp.c | 48 +++++++++++++
gdb/testsuite/gdb.threads/adjacent-bp.exp | 86 +++++++++++++++++++++++
3 files changed, 139 insertions(+), 20 deletions(-)
create mode 100644 gdb/testsuite/gdb.threads/adjacent-bp.c
create mode 100644 gdb/testsuite/gdb.threads/adjacent-bp.exp
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 47966cf72db..a70d88cd4a7 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3100,28 +3100,13 @@ clear_proceed_status_thread (struct thread_info *tp)
infrun_debug_printf ("%s", tp->ptid.to_string ().c_str ());
gdb_assert (tp->internal_state () != THREAD_INT_RUNNING);
- /* If we're starting a new sequence, then the previous finished
- single-step is no longer relevant. */
if (tp->has_pending_waitstatus ())
{
- if (tp->stop_reason () == TARGET_STOPPED_BY_SINGLE_STEP)
- {
- infrun_debug_printf ("pending event of %s was a finished step. "
- "Discarding.",
- tp->ptid.to_string ().c_str ());
-
- tp->set_internal_state (THREAD_INT_STOPPED);
- tp->clear_pending_waitstatus ();
- tp->set_stop_reason (TARGET_STOPPED_BY_NO_REASON);
- }
- else
- {
- infrun_debug_printf
- ("thread %s has pending wait status %s (currently_stepping=%d).",
- tp->ptid.to_string ().c_str (),
- tp->pending_waitstatus ().to_string ().c_str (),
- tp->control.currently_stepping);
- }
+ infrun_debug_printf
+ ("thread %s has pending wait status %s (currently_stepping=%d).",
+ tp->ptid.to_string ().c_str (),
+ tp->pending_waitstatus ().to_string ().c_str (),
+ tp->control.currently_stepping);
}
/* If this signal should not be seen by program, give it zero.
diff --git a/gdb/testsuite/gdb.threads/adjacent-bp.c b/gdb/testsuite/gdb.threads/adjacent-bp.c
new file mode 100644
index 00000000000..e72e674f52a
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/adjacent-bp.c
@@ -0,0 +1,48 @@
+/* Copyright 2026 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include <pthread.h>
+#include <unistd.h>
+
+static pthread_barrier_t barrier;
+
+static void *
+test (void *arg)
+{
+ pthread_barrier_wait (&barrier);
+ int a = 0; /* break here. */
+ int b = 0;
+ int c = 0;
+ return arg;
+}
+
+int
+main ()
+{
+ pthread_t th;
+
+ alarm (500);
+
+ pthread_barrier_init (&barrier, NULL, 2);
+ pthread_create (&th, NULL, test, NULL);
+ test (NULL);
+
+ pthread_join (th, NULL);
+ pthread_barrier_destroy (&barrier);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.threads/adjacent-bp.exp b/gdb/testsuite/gdb.threads/adjacent-bp.exp
new file mode 100644
index 00000000000..9e7782c01c2
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/adjacent-bp.exp
@@ -0,0 +1,86 @@
+# Copyright 2026 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/>.
+
+# Test that GDB does not skip a breakpoint when a step-over completes
+# while another event leads to a stop.
+
+standard_testfile
+
+if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+ {debug pthreads}]} {
+ return
+}
+
+if {![runto_main]} {
+ return
+}
+
+# Find a sequence of adjacent instructions.
+set bp_line [gdb_get_line_number "break here"]
+set pcs {}
+gdb_test_multiple "info line $bp_line" "" {
+ -re -wrap "starts at address ($hex).*" {
+ pass $gdb_test_name
+
+ set line "\\s+($hex) \[^\r\n\]+"
+ gdb_test_multiple "x/3i $expect_out(1,string)" "disassemble" {
+ -re -wrap "$line\r\n$line\r\n$line.*" {
+ pass $gdb_test_name
+
+ lappend pcs $expect_out(1,string)
+ lappend pcs $expect_out(2,string)
+ lappend pcs $expect_out(3,string)
+ }
+ -re -wrap "" {
+ fail $gdb_test_name
+ }
+ }
+ }
+ -re -wrap "" {
+ fail $gdb_test_name
+ }
+}
+
+# Set breakpoints on adjacent instructions.
+foreach pc $pcs {
+ gdb_breakpoint "\*$pc"
+}
+
+# Continue from breakpoint to breakpoint.
+set hits [dict create]
+set iter 0
+gdb_test_multiple "continue" "" {
+ -re -wrap "hit Breakpoint.*" {
+ dict incr hits [get_hexadecimal_valueof "\$pc" invalid "stop $iter"]
+ incr iter
+ send_gdb "continue\n"
+ exp_continue
+ }
+ -re -wrap "$inferior_exited_re normally.*" {
+ pass "$gdb_test_name"
+ }
+}
+
+# We expect all breakpoints to be hit by both threads.
+foreach pc $pcs {
+ if {[dict exists $hits $pc]} {
+ gdb_assert {[dict get $hits $pc] eq 2} "breakpoint at $pc"
+ dict unset hits $pc
+ } else {
+ fail "breakpoint at $pc"
+ }
+}
+# And no unrelated stops.
+gdb_assert {[dict size $hits] eq 0} "no extra stops"
--
2.53.0
________________________________________
Intel Deutschland GmbH
Registered Address: Dornacher Strasse 1, 85622 Feldkirchen, Germany
Tel: +49 (89) 99143-0
www.intel.de
Managing Directors: Candice Moore, Jeffrey Schneiderman, Ramachandran Sitaraman
Chairperson of the Supervisory Board: Sonja Pierer
Registered Seat: Munich Commercial Register B: Amtsgericht Munich HRB 186928
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
next prev parent reply other threads:[~2026-10-01 10:29 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-01 10:28 [RFC PATCH 0/8] breakpoint handling Markus Metzger
2026-10-01 10:28 ` Markus Metzger [this message]
2026-10-01 10:28 ` [RFC PATCH 2/8] gdb, infrun: track last waitstatus per thread Markus Metzger
2026-10-01 10:28 ` [RFC PATCH 3/8] gdb, infrun: simplify print_stop_location() Markus Metzger
2026-10-01 10:28 ` [RFC PATCH 4/8] gdb, thread: simplify print_selected_thread_frame() Markus Metzger
2026-10-01 10:28 ` [RFC PATCH 5/8] gdb, interp: repeat stop event when switching threads Markus Metzger
2026-10-01 10:28 ` [RFC PATCH 6/8] gdb, infrun: handle stop event when selecting a thread Markus Metzger
2026-10-01 10:28 ` [RFC PATCH 7/8] gdb, infrun: inline init_thread_stepping_state() Markus Metzger
2026-10-01 10:28 ` [RFC PATCH 8/8] gdb, infrun: only step over breakpoints that were hit Markus Metzger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261001102847.576880-2-markus.t.metzger@intel.com \
--to=markus.t.metzger@intel.com \
--cc=gdb-patches@sourceware.org \
--cc=guinevere@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox