From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id E7FC63847725 for ; Wed, 3 Apr 2024 20:28:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E7FC63847725 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org E7FC63847725 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712176086; cv=none; b=mgXRxBbS2Jt3pIKbLtNvh870YAi+uCjDoKnDS6OhRPZJIiBvVIfcxUs484gnbgKv/Pinu8rtmMtjJZ26tXpMZgekVNN7ZGe1tpCCifJGuxqj6VUuB3OGEU6PpPm2ZdY7QFP1WdnXX8klyiVqzgjMw+GOlKa/pgxkAPJTmhHs/is= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712176086; c=relaxed/simple; bh=KbhWbhwQSK/VCfyXhhU6ma5gyvlPOHTHvKhqZbqOqIs=; h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:To:From; b=xtX5K5pDptD/zIf3J637Sp5+uIKoFaIsrBQqD0BVUoQaBEOBNr2xMpqkPfRmQlvdOh2Ya77pjDL4EO9w08mxP8immYBURYopD+jivVBT2egdY0qytp++ZbvzC3c5lT4gfjbGLs+aHSuU7OMWVhpG1huBt2sZqrRbMTo1TDWY6Rs= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1712176083; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=COAJR+ipbQ127usMWvEVrwSmEfVhmEhhSc/c6kA2bB4=; b=T2o7j0dKyUvocq2Q1sfhqkWcnSqd6zk+X4OrUfOnD+2BXJcLFCyIbDEF3hBlxQ3iSfVVml VApsFHwpvICo/4VH6phx3/Jfey3eMPCd2jHfvmwy8Yk0WSVm4T9X3/K9NSyI6m4uL9s0HO 3WZk+QWf/zz5rexFdTK39DFxNSk/uKk= Received: from mail-qt1-f200.google.com (mail-qt1-f200.google.com [209.85.160.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-217-Pl7OYk5NPcChm6HCWdCTAQ-1; Wed, 03 Apr 2024 16:28:02 -0400 X-MC-Unique: Pl7OYk5NPcChm6HCWdCTAQ-1 Received: by mail-qt1-f200.google.com with SMTP id d75a77b69052e-430b673a96eso2797291cf.2 for ; Wed, 03 Apr 2024 13:28:02 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1712176081; x=1712780881; h=content-transfer-encoding:in-reply-to:from:content-language :references:to:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=COAJR+ipbQ127usMWvEVrwSmEfVhmEhhSc/c6kA2bB4=; b=ZWydJB0twbrAtc71ZhBulLiByfgYox8mhtxewYMP7E1KnhUkVE9CTlQCGOPR4jkq32 wOmmj9XG1O+tObfyaN8lGH9QA0jLLkDujg7p3HA8mB3jKd2o4yMorMqnmxXStE2DMzfs 2EQ+JOSJTRjzK8YxiJpM/cEs2ngRhMn+jShh+VPP8hMu3d1uILX9QlsZNm8oQ3lKr6NI y9F8B8fu54JpqgE2LLA5OOkxDvdbLeT5riZFfSCoR5vE5xUHMq3L2O+l3zRJpGZiV8w+ 71tnDRzmFC1B/bbup7xM/U8cwAobff0b/8Ko2eyTkpeTLuw7cGoN6UbjSSa7pEXCc2V9 5sJA== X-Forwarded-Encrypted: i=1; AJvYcCXKBr0eVpE8MRJbrTmVVpiD/CDvephjj2pqm35NTxaj1/d4ARKfpGIUrI7Ea05B5dcP4kfIxtflGgOZ5rFA4mdrW0XmE9iJ8lbhqQ== X-Gm-Message-State: AOJu0Ywg2tFenrtalWWweLGx9ELg3b0R6g//ixSeWlutYb/mJjcdyTSN 2Op1rRm4V8wbUG7hbZ3Mv7+BUONOl2FzKxBoaEnBZ2Lys7AjQ7w+0+ZON4y8vXwqC/yYK0pOPVP oFZSBzZODKxkozOrbL0vc9WPEx0ZNwDt/4w+DgcTIEKTVOzWXd6joMbv5TX8= X-Received: by 2002:ac8:5a91:0:b0:431:62a8:491e with SMTP id c17-20020ac85a91000000b0043162a8491emr538193qtc.55.1712176081285; Wed, 03 Apr 2024 13:28:01 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGeB5RQ1gOJVjo2pIG1uiQ7C26Sxab6gwhcBgZhBx0aQ1OWD8GnnwPEiz45J8qo6B9Xm4iW9Q== X-Received: by 2002:ac8:5a91:0:b0:431:62a8:491e with SMTP id c17-20020ac85a91000000b0043162a8491emr538171qtc.55.1712176080802; Wed, 03 Apr 2024 13:28:00 -0700 (PDT) Received: from ?IPV6:2804:14d:8084:92c5::1002? ([2804:14d:8084:92c5::1002]) by smtp.gmail.com with ESMTPSA id bw5-20020a05622a098500b00432bb012607sm6381648qtb.47.2024.04.03.13.27.59 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 03 Apr 2024 13:28:00 -0700 (PDT) Message-ID: <1fd4d2e8-cf01-409c-ba83-dd311b608726@redhat.com> Date: Wed, 3 Apr 2024 17:27:57 -0300 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH v4 4/4] gdb, infrun: fix multi-threaded reverse stepping To: Markus Metzger , gdb-patches@sourceware.org References: <20240312113423.3543956-1-markus.t.metzger@intel.com> <20240312113423.3543956-5-markus.t.metzger@intel.com> From: Guinevere Larsen In-Reply-To: <20240312113423.3543956-5-markus.t.metzger@intel.com> X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_SHORT,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,RCVD_IN_SORBS_WEB,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 List-Id: On 3/12/24 08:34, Markus Metzger wrote: > 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. I'm slowly making my way through this series, but this patch specifically seems to not apply at all. Trying to use git am --3way gives me the following output: Applying: gdb, infrun: fix multi-threaded reverse stepping error: sha1 information is lacking or useless (gdb/infrun.c). error: could not build fake ancestor Patch failed at 0001 gdb, infrun: fix multi-threaded reverse stepping Reviews for the other patches should follow soon -- Cheers, Guinevere Larsen She/Her/Hers > --- > gdb/gdbthread.h | 10 +++ > gdb/infrun.c | 47 ++++++---- > gdb/infrun.h | 7 -- > .../gdb.btrace/implicit-stop-replaying.exp | 90 +++++++++++++++++++ > 4 files changed, 128 insertions(+), 26 deletions(-) > create mode 100644 gdb/testsuite/gdb.btrace/implicit-stop-replaying.exp > > diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h > index 4931a0cc2f1..64f9e231f38 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'. */ > @@ -176,6 +183,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 f92f529412f..9db396821d2 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); > > @@ -2372,11 +2373,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); > > @@ -2527,6 +2529,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); > @@ -2787,6 +2793,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; > @@ -2836,7 +2843,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 (); > } > @@ -2855,7 +2862,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 > @@ -2926,7 +2933,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 > @@ -3095,6 +3102,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 > @@ -3204,7 +3212,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))); > } > > /* Set process_stratum_target::COMMIT_RESUMED_STATE in all target > @@ -3629,7 +3637,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 > @@ -4927,7 +4935,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, > @@ -7526,7 +7534,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; > > @@ -7541,7 +7549,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 > @@ -7666,7 +7674,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 > @@ -7685,7 +7693,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); > @@ -7707,7 +7715,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 > @@ -7856,7 +7864,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 > @@ -7884,7 +7892,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, > @@ -7947,7 +7955,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); > @@ -7965,7 +7973,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 > @@ -7994,7 +8002,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 (); > @@ -8577,6 +8585,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 6339fd997e1..1a52d6250e5 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..20240da1dc1 > --- /dev/null > +++ b/gdb/testsuite/gdb.btrace/implicit-stop-replaying.exp > @@ -0,0 +1,90 @@ > +# 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 "bad" > +gdb_test_multiple "thread" "thread" { > + -re -wrap "Current thread is \($decimal\).*" { > + set thread $expect_out(1,string) > + } > +} > + > +# 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. > +gdb_test "next" "return arg;.*" > + > +# The other thread stopped replaying. > +gdb_test "thread apply $other info record" "Recorded \[^\\\r\\\n\]*" \ > + "other thread stopped replaying"