From patchwork Mon Oct 21 09:56:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Metzger, Markus T" X-Patchwork-Id: 99264 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 29B7A3858289 for ; Mon, 21 Oct 2024 09:57:03 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) by sourceware.org (Postfix) with ESMTPS id 97FA63858D26 for ; Mon, 21 Oct 2024 09:56:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 97FA63858D26 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 97FA63858D26 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729504590; cv=none; b=hUQLhFh3UL2j3/nN+JTGZxqxtxbMw07bOxGDqT18sZflx1GfMAA+7WgKTEl0MVR/Nd1sX85eW01b2/fezCvACLwYz/zCxbBgwUliJ9l4Ef31E5xR0y0qAiR/7MU48alnCDq46AlGjByu176majS+3BRpRE0ChJyrbwEnw+hrI+8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729504590; c=relaxed/simple; bh=nkNaz6vqQX6YXgjsBmLCg5ayqcprkgmDO9CRUAMawmo=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=DwkKd3/+NxKNzmCVJIKBKFna6JzG5pj1uwPISNkJGfLevuNUploDtd6jYCw84/4N5SetyOcBTAoMAhonexepR5AZB4DBA0c5D9OBridk3vro77vhpESnwkxWYZd2jA2sqhdIjDFbgoFnWl8JaK+qStGzaVzTclkBXneBTtQchaM= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1729504579; x=1761040579; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=nkNaz6vqQX6YXgjsBmLCg5ayqcprkgmDO9CRUAMawmo=; b=LUr6qWDRaR2FJNQEhpX888cflxQbxZnx148o4hqDigCh3+WxcaPEfRbH pYZyUyD8K56r5R4QrxvKm/qW3h3famk4tamHg630RJPJcYMhXfYWB5Tbu 3J1z6BQ65jRLDaQnmtLQC8V4pcjRsuwHGVbgZ7rZ7/FGhSS6XTvzAq1gZ Zei6ZhFRn5yuMCQ5MiHY570zCqedgsghu2CmmQqRGeR04xBbzmN2TS36F OCevrLNSh58c+bmqrAs7Bt4zwYXNkt2na3oM70S10cLvOqzmn6jjzuEW3 COc8FVnIj8/ZaVzmSy+eUlJbK2LTvJ5yxq6+oditnR9mpFJlQ+EvnNTAr w==; X-CSE-ConnectionGUID: jjklRMKgR2uaj8+RHJtUcw== X-CSE-MsgGUID: Tn2dCeTVTtCVZQlmtuMCLA== X-IronPort-AV: E=McAfee;i="6700,10204,11231"; a="29077992" X-IronPort-AV: E=Sophos;i="6.11,220,1725346800"; d="scan'208";a="29077992" Received: from fmviesa004.fm.intel.com ([10.60.135.144]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2024 02:56:18 -0700 X-CSE-ConnectionGUID: arPClTF9TpKfdvLsngE+fA== X-CSE-MsgGUID: /jYMn8+FSTCgxhp/ZwuuAw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.11,220,1725346800"; d="scan'208";a="84103217" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2024 02:56:16 -0700 From: Markus Metzger To: gdb-patches@sourceware.org Cc: aburgess@redhat.com, Guinevere Larsen Subject: [PATCH v6 1/4] gdb, infrun, btrace: fix reverse/replay stepping at end of execution history Date: Mon, 21 Oct 2024 09:56:08 +0000 Message-Id: <20241021095611.1126744-2-markus.t.metzger@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241021095611.1126744-1-markus.t.metzger@intel.com> References: <20241021095611.1126744-1-markus.t.metzger@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-9.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org 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~patchwork=sourceware.org@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 73f6895fe46..2d6b212cd32 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -176,6 +176,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; }; /* Inferior thread specific part of `struct infcall_suspend_state'. */ diff --git a/gdb/infrun.c b/gdb/infrun.c index 4ca15450afe..23739e7c009 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -3097,6 +3097,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 @@ -8995,6 +8997,29 @@ keep_going_pass_signal (struct execution_control_state *ecs) gdb_assert (ecs->event_thread->ptid == inferior_ptid); gdb_assert (!ecs->event_thread->resumed ()); + /* 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 8fcf63830b8..626a804046b 100644 --- a/gdb/record-btrace.c +++ b/gdb/record-btrace.c @@ -2386,6 +2386,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 (); @@ -2427,15 +2437,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..628861b265d --- /dev/null +++ b/gdb/testsuite/gdb.btrace/cont-hang.exp @@ -0,0 +1,43 @@ +# 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 . + +# 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..91ea813955d --- /dev/null +++ b/gdb/testsuite/gdb.btrace/step-hang.exp @@ -0,0 +1,42 @@ +# 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 . + +# 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..b999887f526 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/stepn.exp @@ -0,0 +1,50 @@ +# 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 . + +# 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.*" +} From patchwork Mon Oct 21 09:56:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Metzger, Markus T" X-Patchwork-Id: 99263 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 190F13858027 for ; Mon, 21 Oct 2024 09:57:01 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) by sourceware.org (Postfix) with ESMTPS id ED32F3858CDB for ; Mon, 21 Oct 2024 09:56:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org ED32F3858CDB 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 ED32F3858CDB Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729504590; cv=none; b=NVpUTSNJjteRJLUS6zjjFN488CB0x7tecrA7wYJ9GLs/iwdfwxkVzQ1mw/E+KF2imCF+6KhIw5FrwuK7xRa9EFOkaQuNLi8RHDSTnrgXuM/QC1m7YZSNMtDkgOtEkhbCN8ZfAHVTIDilCBmWzqdtu0ISqdBv+ycJINCe69D2QNo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729504590; c=relaxed/simple; bh=+mwaaDUKP98rhMkLLrx+LP5NGbjv0gZNEqRW6i99eE8=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=fGXTzQgPhLfo7s/1fbjrkkGkaGzROu5ceFtmqdE+zVyap6Nc/rfe5aMBTooh1l3GDVO3ZK9vHUdPIwwqXzy8tIeQ90xHjVjF1komTRACSFigCgpikOo1X2QOLRPwk/c0IdsjsSIR2A2cqlhkacG26Yjkjk4j6BRQDe9EEQAG+Og= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1729504582; x=1761040582; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=+mwaaDUKP98rhMkLLrx+LP5NGbjv0gZNEqRW6i99eE8=; b=IEMuKcUgIJMHXBhraFJpRkyj9OE8Mj8lA+QP180mFVavON2f74p+/HXa dZTOJeLX6tJ4q6yTDXez/PN/NGKNg3Z+kIyQDRv5GnHdhIvkdFkGoHy8x LbKbCjmHRvCvB8PjzlbiLVT2dMS2QvwnuLl2XdZCtemd9zeWJrub2i3CR /fl7g2R4lb5lGCQ46cfViOEhKA6HudHbVONTH49zQkcaZkSDqb7hr0Mdk uyrjI/MlEOcmq9Ymo5lJ801+CV2lrcXpM6caEjRSfDLzRNE6u1ddmFWOK 8oPRZ6uZCkQJcaG0wKipd2RVsPoM65itv+xJHh96nH7/woXgPyZPp5XXd g==; X-CSE-ConnectionGUID: xf67hj5/Q6KcAvDA0q5rUA== X-CSE-MsgGUID: OR+N9L9fSiSIYFnzzU0OOQ== X-IronPort-AV: E=McAfee;i="6700,10204,11231"; a="29078006" X-IronPort-AV: E=Sophos;i="6.11,220,1725346800"; d="scan'208";a="29078006" Received: from fmviesa004.fm.intel.com ([10.60.135.144]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2024 02:56:21 -0700 X-CSE-ConnectionGUID: neHTkRUbTpWWEl0swdI5mw== X-CSE-MsgGUID: dcM/oLAhTuSJgopNXjos3g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.11,220,1725346800"; d="scan'208";a="84103236" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2024 02:56:19 -0700 From: Markus Metzger To: gdb-patches@sourceware.org Cc: aburgess@redhat.com, Guinevere Larsen Subject: [PATCH v6 2/4] gdb, infrun, record: fix hang when step-over fails with no-history Date: Mon, 21 Oct 2024 09:56:09 +0000 Message-Id: <20241021095611.1126744-3-markus.t.metzger@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241021095611.1126744-1-markus.t.metzger@intel.com> References: <20241021095611.1126744-1-markus.t.metzger@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-9.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org 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~patchwork=sourceware.org@sourceware.org When trying to step over a breakpoint at the end of the trace while another thread is replaying, 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. This is a variant of the issue fixed in the parent commit. That commit addressed the issue for a single-threaded process and fixed an issue with reverse/replay stepping in general. This commit addresses the issue for a multi-threaded process. In this case, the single-step does not complete. Finish an in-flight step-over when a thread stopped with NO_HISTORY. Since we did not move, we will simply start the step-over again. Hannes Domani reported that this fixes PR gdb/31353. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31353 Reviewed-By: Guinevere Larsen --- gdb/infrun.c | 12 +++ .../gdb.btrace/multi-thread-break-hang.exp | 84 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 gdb/testsuite/gdb.btrace/multi-thread-break-hang.exp diff --git a/gdb/infrun.c b/gdb/infrun.c index 23739e7c009..bad42b45a26 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -78,6 +78,8 @@ #include "disasm.h" #include "interps.h" +struct execution_control_state; + /* Prototypes for local functions */ static void sig_print_info (enum gdb_signal); @@ -6573,6 +6575,16 @@ handle_inferior_event (struct execution_control_state *ecs) return; interps_notify_no_history (); + + /* Cancel an in-flight step-over. It will not succeed since we + won't be able to step at the end of the execution history. */ + { + /* finish_step_over may call restart_threads, which may change the + current thread. make sure we leave the event thread as the + current thread. */ + scoped_restore_current_thread restore_thread; + finish_step_over (ecs); + } stop_waiting (ecs); return; } diff --git a/gdb/testsuite/gdb.btrace/multi-thread-break-hang.exp b/gdb/testsuite/gdb.btrace/multi-thread-break-hang.exp new file mode 100644 index 00000000000..932d1e71956 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/multi-thread-break-hang.exp @@ -0,0 +1,84 @@ +# 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 . + +# Test that we cancel an in-flight step-over at the end of the execution +# history as long as some other thread is still replaying. +# +# This used to cause GDB to hang in poll (). + +require allow_btrace_tests + +standard_testfile multi-thread-step.c +if [prepare_for_testing "failed to prepare" $testfile $srcfile {debug pthreads}] { + return -1 +} + +if ![runto_main] { + return -1 +} + +# Set up breakpoints. +set bp_1 [gdb_get_line_number "bp.1" $srcfile] +set bp_2 [gdb_get_line_number "bp.2" $srcfile] + +# Trace the code between the two breakpoints. +gdb_breakpoint $srcfile:$bp_1 +gdb_continue_to_breakpoint "continue to bp.1" ".*$srcfile:$bp_1\r\n.*" + +gdb_test_no_output "record btrace" + +# We have two threads at or close to bp.1 but handled only one stop event. +# Remove the breakpoint so we do not need to deal with the 2nd event. +delete_breakpoints +gdb_breakpoint $srcfile:$bp_2 +gdb_continue_to_breakpoint "continue to bp.2" ".*$srcfile:$bp_2\r\n.*" + +# Determine the thread that reported the breakpoint. +set thread [get_integer_valueof "\$_thread" bad] + +# Determine the other thread. +set other "bad" +if { $thread == 1 } { + set other 2 +} elseif { $thread == 2 } { + set other 1 +} + +# This test requires scheduler-locking 'on' or 'step'; 'replay' would +# implicitly stop replaying, avoiding the problem; 'off' would step one +# and resume the other. +# +# With the current record-btrace implementation that steps all resumed +# threads in lock-step, 'off' might actually pass but we don't want to +# bake that behavior into tests. +gdb_test_no_output "set scheduler-locking step" + +# Start replaying the other thread. This will prevent stepping the thread +# that reported the event. +gdb_test "thread apply $other record goto begin" +gdb_test "thread apply $other info record" "Replay in progress.*" + +# We're at a breakpoint so this triggers step-over. Since we're at the +# end of the trace, the step will fail. +gdb_test "stepi" "Reached end of recorded history.*" "stepi.1" + +# We used to hang at the second step since step-over insisted on polling +# the next event. +gdb_test "stepi" "Reached end of recorded history.*" "stepi.2" + +# Do one more just in case. +gdb_test "stepi" "Reached end of recorded history.*" "stepi.3" From patchwork Mon Oct 21 09:56:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Metzger, Markus T" X-Patchwork-Id: 99265 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BF69D3858C56 for ; Mon, 21 Oct 2024 09:57:51 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) by sourceware.org (Postfix) with ESMTPS id 5853D3858C50 for ; Mon, 21 Oct 2024 09:56:24 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5853D3858C50 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 5853D3858C50 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729504595; cv=none; b=wYqekhQa+DPlqE1+2bvBzYIbmz6oChbI2bYY5ESxFIg4CsU5AdU9+mCGoa+t3YgZPIpsthFh8Q4zEPuzkR0m7rx3249SNvqy29d33ISZ8gswpQsQhB3VCl/D92g+Kx4ifFv85QQCm8LBjmT5jwGRM6oVuhoeWBJMGdSBZxg4YjI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729504595; c=relaxed/simple; bh=mrPgxjcbYTnT0rLQk44N91m6Tbi3snshJp+rPe2+grg=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=In7SF7igMYFix8Sp3Hr6eF13zjMOeSM4bhFjt8X0tTEKENDjV0VrT/WFm3MWbfg5xfe60xQpgnSB3DDXblZ6S7xJ2lZ3LdDIVSo7ebiQWbwp/EjIgmWhErCKKDWigZ1w+dXs5Sb+vaejhCzSiN7WdyYPhojcmtj1jzG/EiHKnLM= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1729504585; x=1761040585; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mrPgxjcbYTnT0rLQk44N91m6Tbi3snshJp+rPe2+grg=; b=l3+S09APS1JBX1ZY5Gs1bF5Y1oMfdKUpp34+ug7txN1dTw1UZAJWEQxO G5Ok3S+rmJJww9v/Wvmom8RF8yl8PkUUc0qhR+VKP132LeyCVUI+7qvj+ 2nbGswzmhRfW+6EgnNunR/IvlnE5wZTtqGJc3adulJNPpv14QnwnGR4kG VxOKg0LORvV7/6h+Wbv02SOyL23bIzwMsA68TsbjrKauqrgbPMUi2v3Ti T6unqAHLwYwG0STmH403SHSgAcTunov78/nL5rWoVjPf3ByjmOP76ljmL Oah9/0aZBEO3FkEeiSGYESUYXOXQ/kbxku6+eTXboAaorP1QIXueplHvw Q==; X-CSE-ConnectionGUID: BIhCLdm1RHaggu57ygLWrA== X-CSE-MsgGUID: qQWl41hzSbyOPr/a702Nhg== X-IronPort-AV: E=McAfee;i="6700,10204,11231"; a="29078014" X-IronPort-AV: E=Sophos;i="6.11,220,1725346800"; d="scan'208";a="29078014" Received: from fmviesa004.fm.intel.com ([10.60.135.144]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2024 02:56:24 -0700 X-CSE-ConnectionGUID: jA74u0mAQP6XH8TbD7eznw== X-CSE-MsgGUID: f8YJF9yuTi6fTHZtESUrwA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.11,220,1725346800"; d="scan'208";a="84103258" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2024 02:56:23 -0700 From: Markus Metzger To: gdb-patches@sourceware.org Cc: aburgess@redhat.com, Guinevere Larsen Subject: [PATCH v6 3/4] gdb, infrun, record: move no-history notification into normal_stop Date: Mon, 21 Oct 2024 09:56:10 +0000 Message-Id: <20241021095611.1126744-4-markus.t.metzger@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241021095611.1126744-1-markus.t.metzger@intel.com> References: <20241021095611.1126744-1-markus.t.metzger@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-9.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org 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~patchwork=sourceware.org@sourceware.org Leave calling gdb::observers::no_history.notify to normal_stop based on the last waitstatus. Reviewed-By: Guinevere Larsen --- gdb/infrun.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gdb/infrun.c b/gdb/infrun.c index bad42b45a26..743a500595c 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -6574,8 +6574,6 @@ handle_inferior_event (struct execution_control_state *ecs) if (handle_stop_requested (ecs)) return; - interps_notify_no_history (); - /* Cancel an in-flight step-over. It will not succeed since we won't be able to step at the end of the execution history. */ { @@ -9023,7 +9021,6 @@ keep_going_pass_signal (struct execution_control_state *ecs) 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; @@ -9682,6 +9679,9 @@ normal_stop () if (saved_context.changed ()) return true; + if (last.kind () == TARGET_WAITKIND_NO_HISTORY) + interps_notify_no_history (); + /* Notify observers about the stop. This is where the interpreters print the stop event. */ notify_normal_stop ((inferior_ptid != null_ptid From patchwork Mon Oct 21 09:56:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Metzger, Markus T" X-Patchwork-Id: 99266 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 979773858C42 for ; Mon, 21 Oct 2024 09:58:13 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) by sourceware.org (Postfix) with ESMTPS id BB2213858C31 for ; Mon, 21 Oct 2024 09:56:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BB2213858C31 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 BB2213858C31 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729504602; cv=none; b=ppGL/XdHxf8S3CaNp5t66N/9TUFsXwa8aIN+3/0dJo9Ocg505bmGiegbdDPUqCOQwv2eznCHpAnB25F9ukxUDosz56vtxQYj6wRU/VuYGT988Q4z1/8UbdD+AVTRVSeRNCRMkUjb5Gm5F+/1HYtzFkwgIjeju0THKn9KignLXVI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729504602; c=relaxed/simple; bh=AyWPM7Tv/DfdQXz+WL0vTvtcugVMEogfI0/sI0/b7sA=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=nkp4+DuUlJ1laBPHoql5p/3iZZm3TIfRSooy2h7q0T5GzB2WZSDOT0XN0zd65zwHplHbIqB0FFYU2cR/i28pQ7J3NwgOzH0/XeV+zrLuevPGwWIUvLCzcj63yLVurxHRuNuU1rtSTZXbd2SW4jZgByB/Ke9v0x+MjIyh5OwzdrY= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1729504591; x=1761040591; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=AyWPM7Tv/DfdQXz+WL0vTvtcugVMEogfI0/sI0/b7sA=; b=ByIDASdNTsT0w+UBn8PVzh8C5WpGIaLO+D2Y00jkozT1eRXvht+ilbjq XCKjgaM5yWh/qYZUSjh6SkIWmnSAMLdBZgliInSzqPuJErpUXFy+603J/ rU+4JxSt4orYBTTokaYpeHraaVqamuzOErsIPTwCtzz5wPLaDJ5hvYwvE ZnYYiOtW+iefnfTxlNDpahzoZThAzcZ5IyCXUvGz/5z9yl2L8uXBP7sos f5HydtdDMaFBWxvtSSdW+hdWBJ4rB3qk0mdPwFruVkCwAVBw15GHmi61Y 6MZUKD5COYvvwRQz6FbQ+p2/d86ws4h/Hn1Vhm5/Dd14kOZjobMvX/4zj A==; X-CSE-ConnectionGUID: 6yNWvG5JTcSmj5H91/F9oA== X-CSE-MsgGUID: UZm0HKEIQIGcR0OJxkKqLA== X-IronPort-AV: E=McAfee;i="6700,10204,11231"; a="29078023" X-IronPort-AV: E=Sophos;i="6.11,220,1725346800"; d="scan'208";a="29078023" Received: from fmviesa004.fm.intel.com ([10.60.135.144]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2024 02:56:28 -0700 X-CSE-ConnectionGUID: RTu5oBKBQRGdIZFUIUO7zQ== X-CSE-MsgGUID: OM9uTkDcSuyNScp9ysX57g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.11,220,1725346800"; d="scan'208";a="84103278" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2024 02:56:26 -0700 From: Markus Metzger To: gdb-patches@sourceware.org Cc: aburgess@redhat.com, Guinevere Larsen Subject: [PATCH v6 4/4] gdb, infrun: fix multi-threaded reverse stepping Date: Mon, 21 Oct 2024 09:56:11 +0000 Message-Id: <20241021095611.1126744-5-markus.t.metzger@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241021095611.1126744-1-markus.t.metzger@intel.com> References: <20241021095611.1126744-1-markus.t.metzger@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-9.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org 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~patchwork=sourceware.org@sourceware.org When reverse-stepping a thread that has a pending breakpoint event, the thread is not resumed as part of the infcmd function. A first resume notices the event and returns without resuming the target. If the corresponding breakpoint has been deleted, event processing results in a second resume that performs the intended stepping action. That resume happens after the infcmd function returned and the temporarily modified execution direction was restored. We end up resuming in the wrong direction. Store the direction in a thread's control state and change most of infrun to take it from there rather than using the global variable. Reviewed-By: Guinevere Larsen --- gdb/gdbthread.h | 10 ++ gdb/infrun.c | 55 ++++++---- gdb/infrun.h | 7 -- .../gdb.btrace/implicit-stop-replaying.exp | 101 ++++++++++++++++++ 4 files changed, 143 insertions(+), 30 deletions(-) create mode 100644 gdb/testsuite/gdb.btrace/implicit-stop-replaying.exp diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h index 2d6b212cd32..12773c7bb12 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -92,6 +92,13 @@ enum step_over_calls_kind STEP_OVER_UNDEBUGGABLE }; +/* Reverse execution. */ +enum exec_direction_kind + { + EXEC_FORWARD, + EXEC_REVERSE + }; + /* Inferior thread specific part of `struct infcall_control_state'. Inferior process counterpart is `struct inferior_control_state'. */ @@ -179,6 +186,9 @@ struct thread_control_state /* Whether the thread was replaying when the command was issued. */ bool is_replaying = false; + + /* The execution direction when the command was issued. */ + enum exec_direction_kind execution_direction = EXEC_FORWARD; }; /* Inferior thread specific part of `struct infcall_suspend_state'. */ diff --git a/gdb/infrun.c b/gdb/infrun.c index 743a500595c..68ecd7fac3e 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -96,7 +96,8 @@ static void insert_step_resume_breakpoint_at_caller (const frame_info_ptr &); static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR); -static bool maybe_software_singlestep (struct gdbarch *gdbarch); +static bool maybe_software_singlestep (const thread_info *tp, + gdbarch *gdbarch, CORE_ADDR pc); static void resume (gdb_signal sig); @@ -2370,11 +2371,12 @@ bool sched_multi = false; GDBARCH the current gdbarch. */ static bool -maybe_software_singlestep (struct gdbarch *gdbarch) +maybe_software_singlestep (const thread_info *tp, gdbarch *gdbarch, + CORE_ADDR pc) { bool hw_step = true; - if (execution_direction == EXEC_FORWARD + if (tp->control.execution_direction == EXEC_FORWARD && gdbarch_software_single_step_p (gdbarch)) hw_step = !insert_single_step_breakpoints (gdbarch); @@ -2533,6 +2535,10 @@ do_target_resume (ptid_t resume_ptid, bool step, enum gdb_signal sig) /* Install inferior's terminal modes. */ target_terminal::inferior (); + scoped_restore save_exec_dir + = make_scoped_restore (&execution_direction, + tp->control.execution_direction); + /* Avoid confusing the next resume, if the next stop/resume happens to apply to another thread. */ tp->set_stop_signal (GDB_SIGNAL_0); @@ -2793,6 +2799,7 @@ resume_1 (enum gdb_signal sig) insert_breakpoints (); resume_ptid = internal_resume_ptid (user_step); + do_target_resume (resume_ptid, false, GDB_SIGNAL_0); tp->set_resumed (true); return; @@ -2842,7 +2849,7 @@ resume_1 (enum gdb_signal sig) set_step_over_info (aspace, regcache_read_pc (regcache), 0, tp->global_num); - step = maybe_software_singlestep (gdbarch); + step = maybe_software_singlestep (tp, gdbarch, pc); insert_breakpoints (); } @@ -2861,7 +2868,7 @@ resume_1 (enum gdb_signal sig) /* Do we need to do it the hard way, w/temp breakpoints? */ else if (step) - step = maybe_software_singlestep (gdbarch); + step = maybe_software_singlestep (tp, gdbarch, pc); /* Currently, our software single-step implementation leads to different results than hardware single-stepping in one situation: when stepping @@ -2932,7 +2939,7 @@ resume_1 (enum gdb_signal sig) else resume_ptid = internal_resume_ptid (user_step); - if (execution_direction != EXEC_REVERSE + if (tp->control.execution_direction != EXEC_REVERSE && step && breakpoint_inserted_here_p (aspace, pc)) { /* There are two cases where we currently need to step a @@ -3101,6 +3108,7 @@ clear_proceed_status_thread (struct thread_info *tp) bpstat_clear (&tp->control.stop_bpstat); tp->control.is_replaying = target_record_is_replaying (tp->ptid); + tp->control.execution_direction = ::execution_direction; } /* Notify the current interpreter and observers that the target is about to @@ -3210,7 +3218,7 @@ schedlock_applies (struct thread_info *tp) && tp->control.stepping_command) || (scheduler_mode == schedlock_replay && target_record_will_replay (minus_one_ptid, - execution_direction))); + tp->control.execution_direction))); } /* When FORCE_P is false, set process_stratum_target::COMMIT_RESUMED_STATE @@ -3647,7 +3655,7 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) if (cur_thr->stop_pc_p () && pc == cur_thr->stop_pc () && breakpoint_here_p (aspace, pc) == ordinary_breakpoint_here - && execution_direction != EXEC_REVERSE) + && cur_thr->control.execution_direction != EXEC_REVERSE) /* There is a breakpoint at the address we will resume at, step one instruction before inserting breakpoints so that we do not stop right away (and report a second hit at this @@ -4963,7 +4971,7 @@ adjust_pc_after_break (struct thread_info *thread, breakpoint at PC - 1. We'd then report a hit on B1, although INSN1 hadn't been de-executed yet. Doing nothing is the correct behaviour. */ - if (execution_direction == EXEC_REVERSE) + if (thread->control.execution_direction == EXEC_REVERSE) return; /* If the target can tell whether the thread hit a SW breakpoint, @@ -7551,7 +7559,7 @@ process_event_stop_test (struct execution_control_state *ecs) delete_step_resume_breakpoint (ecs->event_thread); if (ecs->event_thread->control.proceed_to_finish - && execution_direction == EXEC_REVERSE) + && ecs->event_thread->control.execution_direction == EXEC_REVERSE) { struct thread_info *tp = ecs->event_thread; @@ -7566,7 +7574,7 @@ process_event_stop_test (struct execution_control_state *ecs) } fill_in_stop_func (gdbarch, ecs); if (ecs->event_thread->stop_pc () == ecs->stop_func_start - && execution_direction == EXEC_REVERSE) + && ecs->event_thread->control.execution_direction == EXEC_REVERSE) { /* We are stepping over a function call in reverse, and just hit the step-resume breakpoint at the start address of @@ -7686,7 +7694,7 @@ process_event_stop_test (struct execution_control_state *ecs) if (pc_in_thread_step_range (ecs->event_thread->stop_pc (), ecs->event_thread) - && (execution_direction != EXEC_REVERSE + && (ecs->event_thread->control.execution_direction != EXEC_REVERSE || *curr_frame_id == original_frame_id)) { infrun_debug_printf @@ -7705,7 +7713,7 @@ process_event_stop_test (struct execution_control_state *ecs) CORE_ADDR stop_pc = ecs->event_thread->stop_pc (); if (stop_pc == ecs->event_thread->control.step_range_start && stop_pc != ecs->stop_func_start - && execution_direction == EXEC_REVERSE) + && ecs->event_thread->control.execution_direction == EXEC_REVERSE) end_stepping_range (ecs); else keep_going (ecs); @@ -7727,7 +7735,7 @@ process_event_stop_test (struct execution_control_state *ecs) backward through the trampoline code, and that's handled further down, so there is nothing for us to do here. */ - if (execution_direction != EXEC_REVERSE + if (ecs->event_thread->control.execution_direction != EXEC_REVERSE && ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE && in_solib_dynsym_resolve_code (ecs->event_thread->stop_pc ()) && (ecs->event_thread->control.step_start_function == nullptr @@ -7876,7 +7884,7 @@ process_event_stop_test (struct execution_control_state *ecs) /* Reverse stepping through solib trampolines. */ - if (execution_direction == EXEC_REVERSE + if (ecs->event_thread->control.execution_direction == EXEC_REVERSE && ecs->event_thread->control.step_over_calls != STEP_OVER_NONE && (gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc) || (ecs->stop_func_start == 0 @@ -7904,7 +7912,7 @@ process_event_stop_test (struct execution_control_state *ecs) stepped into (backwards), and continue to there. When we get there, we'll need to single-step back to the caller. */ - if (execution_direction == EXEC_REVERSE) + if (ecs->event_thread->control.execution_direction == EXEC_REVERSE) { /* If we're already at the start of the function, we've either just stepped backward into a single instruction function, @@ -7967,7 +7975,7 @@ process_event_stop_test (struct execution_control_state *ecs) tmp_sal) && !inline_frame_is_marked_for_skip (true, ecs->event_thread)) { - if (execution_direction == EXEC_REVERSE) + if (ecs->event_thread->control.execution_direction == EXEC_REVERSE) handle_step_into_function_backward (gdbarch, ecs); else handle_step_into_function (gdbarch, ecs); @@ -7985,7 +7993,7 @@ process_event_stop_test (struct execution_control_state *ecs) return; } - if (execution_direction == EXEC_REVERSE) + if (ecs->event_thread->control.execution_direction == EXEC_REVERSE) { /* If we're already at the start of the function, we've either just stepped backward into a single instruction function without line @@ -8014,7 +8022,7 @@ process_event_stop_test (struct execution_control_state *ecs) /* Reverse stepping through solib trampolines. */ - if (execution_direction == EXEC_REVERSE + if (ecs->event_thread->control.execution_direction == EXEC_REVERSE && ecs->event_thread->control.step_over_calls != STEP_OVER_NONE) { CORE_ADDR stop_pc = ecs->event_thread->stop_pc (); @@ -8088,7 +8096,7 @@ process_event_stop_test (struct execution_control_state *ecs) } } - if (execution_direction == EXEC_REVERSE + if (ecs->event_thread->control.execution_direction == EXEC_REVERSE && ecs->event_thread->control.proceed_to_finish && ecs->event_thread->stop_pc () >= ecs->stop_func_alt_start && ecs->event_thread->stop_pc () < ecs->stop_func_start) @@ -8200,7 +8208,7 @@ process_event_stop_test (struct execution_control_state *ecs) if (stop_pc_sal.is_stmt) { - if (execution_direction == EXEC_REVERSE) + if (ecs->event_thread->control.execution_direction == EXEC_REVERSE) { /* We are stepping backwards make sure we have reached the beginning of the line. */ @@ -8258,7 +8266,7 @@ process_event_stop_test (struct execution_control_state *ecs) } } - if (execution_direction == EXEC_REVERSE + if (ecs->event_thread->control.execution_direction == EXEC_REVERSE && *curr_frame_id != original_frame_id && original_frame_id.code_addr_p && curr_frame_id->code_addr_p && original_frame_id.code_addr == curr_frame_id->code_addr) @@ -8299,7 +8307,7 @@ process_event_stop_test (struct execution_control_state *ecs) infrun_debug_printf ("keep going"); - if (execution_direction == EXEC_REVERSE) + if (ecs->event_thread->control.execution_direction == EXEC_REVERSE) { CORE_ADDR stop_pc = ecs->event_thread->stop_pc (); @@ -8598,6 +8606,7 @@ keep_going_stepped_thread (struct thread_info *tp) tp->set_resumed (true); resume_ptid = internal_resume_ptid (tp->control.stepping_command); + do_target_resume (resume_ptid, false, GDB_SIGNAL_0); } else diff --git a/gdb/infrun.h b/gdb/infrun.h index 5f83ca2b4c3..c3d27c3dea3 100644 --- a/gdb/infrun.h +++ b/gdb/infrun.h @@ -107,13 +107,6 @@ extern bool disable_randomization; current location. */ extern ULONGEST get_stop_id (void); -/* Reverse execution. */ -enum exec_direction_kind - { - EXEC_FORWARD, - EXEC_REVERSE - }; - /* The current execution direction. */ extern enum exec_direction_kind execution_direction; diff --git a/gdb/testsuite/gdb.btrace/implicit-stop-replaying.exp b/gdb/testsuite/gdb.btrace/implicit-stop-replaying.exp new file mode 100644 index 00000000000..e751aaa98df --- /dev/null +++ b/gdb/testsuite/gdb.btrace/implicit-stop-replaying.exp @@ -0,0 +1,101 @@ +# 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 . + +# Test that we stop replaying other threads when stepping a thread at the +# end of its execution history. +# +# This is similar to the last test in multi-thread-step.exp, except that +# we reverse-step instead of record goto begin to start replaying and we +# step instead of continuing. +# +# This triggered a bug where GDB confused the execution direction and kept +# stepping both threads backwards instead of forwards. + +require allow_btrace_tests + +standard_testfile multi-thread-step.c +if [prepare_for_testing "failed to prepare" $testfile $srcfile \ + {debug pthreads}] { + return -1 +} + +if ![runto_main] { + return -1 +} + +# Set up breakpoints. +set bp_1 [gdb_get_line_number "bp.1" $srcfile] +set bp_2 [gdb_get_line_number "bp.2" $srcfile] + +# Trace the code between the two breakpoints. +gdb_breakpoint $srcfile:$bp_1 +gdb_continue_to_breakpoint "continue to bp.1" ".*$srcfile:$bp_1\r\n.*" + +# Make sure GDB knows about the new thread. +gdb_test "info threads" +gdb_test_no_output "record btrace" + +# We have two threads at or close to bp.1 but handled only one stop event. +# Remove the breakpoint so we do not need to deal with the 2nd event. +delete_breakpoints +gdb_breakpoint $srcfile:$bp_2 +gdb_continue_to_breakpoint "continue to bp.2" ".*$srcfile:$bp_2\r\n.*" + +# Determine the thread that reported the breakpoint. +set thread [get_integer_valueof "\$_thread" bad] + +# Determine the other thread. +set other "bad" +if { $thread == 1 } { + set other 2 +} elseif { $thread == 2 } { + set other 1 +} + +# This test only works for scheduler-locking 'replay'. +gdb_test_no_output "set scheduler-locking replay" + +# Remove breakpoints or we might run into it right away. +delete_breakpoints + +# Start replaying the other thread. +gdb_test "thread apply $other reverse-stepi" +gdb_test "thread apply $other info record" "Replay in progress.*" \ + "other thread is replaying" + +# Step the thread that reported the breakpoint, which is not replaying. +# +# There is a chance that the other thread exits while we step. We could +# slow it down to make this less likely, but we can also handle this case. +set other_exited 0 +gdb_test_multiple "next" {} { + -re "Thread.*exited" { + set other_exited 1 + exp_continue + } + -re -wrap "return arg;.*" { + pass $gdb_test_name + } +} + +# The other thread stopped replaying. If it still exists. +if {$other_exited == 1} { + pass "other thread stopped replaying" +} else { + gdb_test "thread apply $other info record" "Recorded \[^\\\r\\\n\]*" \ + "other thread stopped replaying" +}