From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id VBoeKwc932krjxgAWB0awg (envelope-from ) for ; Wed, 15 Apr 2026 03:23:51 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=YC0G70ny; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 8E12F1E0C3; Wed, 15 Apr 2026 03:23:51 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 9AC9E1E0B1 for ; Wed, 15 Apr 2026 03:23:49 -0400 (EDT) Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 3025F4BA2E0A for ; Wed, 15 Apr 2026 07:23:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3025F4BA2E0A Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=YC0G70ny Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.8]) by sourceware.org (Postfix) with ESMTPS id 376E24BA2E0A for ; Wed, 15 Apr 2026 07:23:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 376E24BA2E0A Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 376E24BA2E0A Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=192.198.163.8 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776237798; cv=none; b=CsmJp2OGKQRQTSl4lSWSdtR0+hxYe4t0krU3e4Tt3FakG/LIab8+bPcSTDgUlDXiWdgvqwC/+lsuWgH16bI2+JX0vCfK9nUrqmghCqEkfZvXMkxgNbel/4Iv7sYtM56GmbGFSeLjonKlu8ciB1xffs0WEIV4+PzkoO/FV0BKqSM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776237798; c=relaxed/simple; bh=x9v7IjvJ4bKfzBi8UBVYjGrIFezyxwxVtdGiVBQ8+y4=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=gxRoK1XzV1fPrm+QYMPvbvVnFUOU6UG1ICn9trAbsvk3C3q+a95I+bhQJGsgrsQwqCz52KUvCxPflW5JsQX/Zau2fh4fWfrEqFBHKae7DYeRtJJOpPrsefDwX7x5FSbD4hVG5Khig/Sqp0NGA7cHcn7YY34FT0WVBhfN78Iv10o= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 376E24BA2E0A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1776237798; x=1807773798; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=x9v7IjvJ4bKfzBi8UBVYjGrIFezyxwxVtdGiVBQ8+y4=; b=YC0G70nyYetPLF1P4Z5qGfb2oAH93oMKFsPg0c3QoWW+WSAXfTKpru5D QztsbykI6Dhgn8t6aNqzSt+C3xQKkfqovEcRNffk79xa3SqA6l0jUC6ii oB45F8jymM/4oKPu8dCKXnisVmRQdm/+qGlRs50nFFP1r5V2qkGZacNZR cVRdC9vUchKBmAcQeUUB7A/xnmrrY1bXNjwUGE+fOOWUArLNhVTnSkDEe Zms9CechcMRJzM3LwqpHOC6I/mTvdLxW7StxmVf5p+4UQMROTgVK8qdOx n8hFbGfm2C5U/+zhKz3AbOGsheuTPNokQopX4dawiOAo4LPwnJAnlAuui A==; X-CSE-ConnectionGUID: AyyALYWPTdeddIR3cnH1sw== X-CSE-MsgGUID: vGIOm1AiR7C630DW5mzniw== X-IronPort-AV: E=McAfee;i="6800,10657,11759"; a="94776398" X-IronPort-AV: E=Sophos;i="6.23,179,1770624000"; d="scan'208";a="94776398" Received: from orviesa009.jf.intel.com ([10.64.159.149]) by fmvoesa102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Apr 2026 00:23:17 -0700 X-CSE-ConnectionGUID: s1ECC69VS6+gcawdrco8Nw== X-CSE-MsgGUID: ZstYx9fmRiizD8M08Jf5hQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,179,1770624000"; d="scan'208";a="230194871" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by orviesa009-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Apr 2026 00:23:16 -0700 From: Markus Metzger To: gdb-patches@sourceware.org Cc: Guinevere Larsen Subject: [PATCH v8 1/4] gdb, infrun, btrace: fix reverse/replay stepping at end of execution history Date: Wed, 15 Apr 2026 07:23:08 +0000 Message-Id: <20260415072311.3597558-2-markus.t.metzger@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260415072311.3597558-1-markus.t.metzger@intel.com> References: <20260415072311.3597558-1-markus.t.metzger@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org When trying to step over a breakpoint at the end of the trace, the step-over will fail with no-history. This does not clear step_over_info so a subsequent resume will cause GDB to not resume the thread and expect a SIGTRAP to complete the step-over. This will never come causing GDB to hang in the wait-for-event poll. That step-over failed after actually completing the step. This is wrong. The step-over itself should have failed and the step should not have completed. Fix it by moving the end of execution history check to before we are stepping. This exposes another issue, however. When completing a step-over at the end of the execution history, we implicitly stop replaying that thread. A continue command would resume after the step-over and, since we're no longer replaying, would continue recording. Fix that by recording the replay state in the thread's control state and failing with no-history in keep_going if we're switching from replay to recording. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31353 Reviewed-By: Guinevere Larsen --- gdb/gdbthread.h | 3 ++ gdb/infrun.c | 25 +++++++++++++ gdb/record-btrace.c | 19 +++++----- gdb/testsuite/gdb.btrace/cont-hang.exp | 43 ++++++++++++++++++++++ gdb/testsuite/gdb.btrace/step-hang.exp | 42 ++++++++++++++++++++++ gdb/testsuite/gdb.btrace/stepn.exp | 50 ++++++++++++++++++++++++++ 6 files changed, 173 insertions(+), 9 deletions(-) create mode 100644 gdb/testsuite/gdb.btrace/cont-hang.exp create mode 100644 gdb/testsuite/gdb.btrace/step-hang.exp create mode 100644 gdb/testsuite/gdb.btrace/stepn.exp diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h index c56c4ce4036..5c8f498347d 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -237,6 +237,9 @@ struct thread_control_state /* True if the thread is evaluating a BP condition. */ bool in_cond_eval = false; + /* Whether the thread was replaying when the command was issued. */ + bool is_replaying = false; + private: /* Function the thread was in as of last it started stepping. */ struct symbol *m_step_start_function = nullptr; diff --git a/gdb/infrun.c b/gdb/infrun.c index 19836c4d89e..daddcc14f90 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -3109,6 +3109,8 @@ clear_proceed_status_thread (struct thread_info *tp) /* Discard any remaining commands or status from previous stop. */ bpstat_clear (&tp->control.stop_bpstat); + + tp->control.is_replaying = target_record_is_replaying (tp->ptid); } /* Notify the current interpreter and observers that the target is about to @@ -9049,6 +9051,29 @@ keep_going_pass_signal (struct execution_control_state *ecs) gdb_assert (ecs->event_thread->ptid == inferior_ptid); gdb_assert (ecs->event_thread->internal_state () == THREAD_INT_STOPPED); + /* When a thread reaches the end of its execution history, it automatically + stops replaying. This is so the user doesn't need to explicitly stop it + with a separate command. + + We do not want a single command (e.g. continue) to transition from + replaying to recording, though, e.g. when starting from a breakpoint we + needed to step over at the end of the trace. When we reach the end of the + execution history during stepping, stop with no-history. + + The other direction is fine. When we're at the end of the execution + history, we may reverse-continue to start replaying. */ + if (ecs->event_thread->control.is_replaying + && !target_record_is_replaying (ecs->event_thread->ptid)) + { + interps_notify_no_history (); + ecs->ws.set_no_history (); + set_last_target_status (ecs->target, ecs->ptid, ecs->ws); + stop_print_frame = true; + stop_waiting (ecs); + normal_stop (); + return; + } + /* Save the pc before execution, to compare with pc after stop. */ ecs->event_thread->prev_pc = regcache_read_pc_protected (get_thread_regcache (ecs->event_thread)); diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c index b4f1dcc3dea..785f052d6d2 100644 --- a/gdb/record-btrace.c +++ b/gdb/record-btrace.c @@ -2367,6 +2367,16 @@ record_btrace_single_step_forward (struct thread_info *tp) if (replay == NULL) return btrace_step_no_history (); + /* The execution trace contains (and ends with) the current instruction. + This instruction has not been executed, yet, so the trace really ends + one instruction earlier. + + We'd fail later on in btrace_insn_next () but we must not trigger + breakpoints as we're not really able to step. */ + btrace_insn_end (&end, btinfo); + if (btrace_insn_cmp (replay, &end) == 0) + return btrace_step_no_history (); + /* Check if we're stepping a breakpoint. */ if (record_btrace_replay_at_breakpoint (tp)) return btrace_step_stopped (); @@ -2408,15 +2418,6 @@ record_btrace_single_step_forward (struct thread_info *tp) break; } - /* Determine the end of the instruction trace. */ - btrace_insn_end (&end, btinfo); - - /* The execution trace contains (and ends with) the current instruction. - This instruction has not been executed, yet, so the trace really ends - one instruction earlier. */ - if (btrace_insn_cmp (replay, &end) == 0) - return btrace_step_no_history (); - return btrace_step_spurious (); } diff --git a/gdb/testsuite/gdb.btrace/cont-hang.exp b/gdb/testsuite/gdb.btrace/cont-hang.exp new file mode 100644 index 00000000000..a172157b508 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/cont-hang.exp @@ -0,0 +1,43 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2025 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 . + +# Test that we do not hang when trying to continue over a breakpoint at +# the end of the trace. + +require allow_btrace_tests + +standard_testfile record_goto.c +if {[prepare_for_testing "failed to prepare" $testfile $srcfile]} { + return -1 +} + +if {![runto_main]} { + return -1 +} + +# Trace the call to the test function. +gdb_test_no_output "record btrace" +gdb_test "next" "main\.3.*" + +# We need to be replaying, otherwise, we'd just continue recording. +gdb_test "reverse-stepi" +gdb_test "break" + +# Continuing will step over the breakpoint and then run into the end of +# the execution history. This ends replay, so we can continue recording. +gdb_test "continue" "Reached end of recorded history.*" +gdb_continue_to_end diff --git a/gdb/testsuite/gdb.btrace/step-hang.exp b/gdb/testsuite/gdb.btrace/step-hang.exp new file mode 100644 index 00000000000..26b7304d2cc --- /dev/null +++ b/gdb/testsuite/gdb.btrace/step-hang.exp @@ -0,0 +1,42 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2025 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 . + +# Test that we do not hang when trying to step over a breakpoint at the +# end of the trace. + +require allow_btrace_tests + +standard_testfile record_goto.c +if {[prepare_for_testing "failed to prepare" $testfile $srcfile]} { + return -1 +} + +if {![runto_main]} { + return -1 +} + +# Trace the call to the test function. +gdb_test_no_output "record btrace" +gdb_test "next" "main\.3.*" + +# We need to be replaying, otherwise, we'd just continue recording. +gdb_test "reverse-stepi" +gdb_test "break" + +# Stepping over the breakpoint ends replaying and we can continue recording. +gdb_test "step" "main\.3.*" +gdb_continue_to_end diff --git a/gdb/testsuite/gdb.btrace/stepn.exp b/gdb/testsuite/gdb.btrace/stepn.exp new file mode 100644 index 00000000000..7989277b38c --- /dev/null +++ b/gdb/testsuite/gdb.btrace/stepn.exp @@ -0,0 +1,50 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2025 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 . + +# Test that step n does not start recording when issued while replaying. + +require allow_btrace_tests + +standard_testfile record_goto.c +if {[prepare_for_testing "failed to prepare" $testfile $srcfile]} { + return -1 +} + +if {![runto_main]} { + return -1 +} + +# Trace the call to the test function. +gdb_test_no_output "record btrace" +gdb_test "next" "main\.3.*" + +# Stepping should bring us to the end of the execution history, but should +# not resume recording. +with_test_prefix "stepi" { + gdb_test "reverse-stepi" + gdb_test "stepi 5" "Reached end of recorded history.*main\.3.*" +} + +with_test_prefix "step" { + gdb_test "reverse-step" + gdb_test "step 5" "Reached end of recorded history.*main\.3.*" +} + +with_test_prefix "next" { + gdb_test "reverse-next" + gdb_test "next 5" "Reached end of recorded history.*main\.3.*" +} -- 2.34.1 Intel Deutschland GmbH Registered Address: Dornacher Strasse 1, 85622 Feldkirchen, Germany Tel: +49 89 991 430, www.intel.de Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell Chairperson of the Supervisory Board: Nicole Lau Registered Seat: Munich Commercial Register: Amtsgericht Muenchen HRB 186928