From patchwork Tue Apr 7 12:49:40 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 6062 Received: (qmail 78465 invoked by alias); 7 Apr 2015 12:59:25 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 78379 invoked by uid 89); 7 Apr 2015 12:59:24 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, SPF_HELO_PASS, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Tue, 07 Apr 2015 12:59:20 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (Postfix) with ESMTPS id C297A9175F for ; Tue, 7 Apr 2015 12:50:05 +0000 (UTC) Received: from brno.lan (ovpn01.gateway.prod.ext.ams2.redhat.com [10.39.146.11]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t37Cnowx022139 for ; Tue, 7 Apr 2015 08:50:05 -0400 From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH v2 13/23] Factor out code to re-resume stepped thread Date: Tue, 7 Apr 2015 13:49:40 +0100 Message-Id: <1428410990-28560-14-git-send-email-palves@redhat.com> In-Reply-To: <1428410990-28560-1-git-send-email-palves@redhat.com> References: <1428410990-28560-1-git-send-email-palves@redhat.com> Just a code refactor, no funcionality change intended. gdb/ChangeLog: 2015-04-07 Pedro Alves * infrun.c (keep_going_stepped_thread): New function, factored out from ... (switch_back_to_stepped_thread): ... here. --- gdb/infrun.c | 198 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 106 insertions(+), 92 deletions(-) diff --git a/gdb/infrun.c b/gdb/infrun.c index 87bbe03..f24e8d7 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1879,6 +1879,7 @@ reset_ecs (struct execution_control_state *ecs, struct thread_info *tp) static void keep_going_pass (struct execution_control_state *ecs); static void prepare_to_wait (struct execution_control_state *ecs); +static int keep_going_stepped_thread (struct thread_info *tp); static int thread_still_needs_step_over (struct thread_info *tp); /* Are there any pending step-over requests for INF? If so, run one @@ -5753,110 +5754,123 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) if (stepping_thread != NULL) { - struct frame_info *frame; - struct gdbarch *gdbarch; - - tp = stepping_thread; - - /* If the stepping thread exited, then don't try to switch - back and resume it, which could fail in several different - ways depending on the target. Instead, just keep going. - - We can find a stepping dead thread in the thread list in - two cases: - - - The target supports thread exit events, and when the - target tries to delete the thread from the thread list, - inferior_ptid pointed at the exiting thread. In such - case, calling delete_thread does not really remove the - thread from the list; instead, the thread is left listed, - with 'exited' state. - - - The target's debug interface does not support thread - exit events, and so we have no idea whatsoever if the - previously stepping thread is still alive. For that - reason, we need to synchronously query the target - now. */ - if (is_exited (tp->ptid) - || !target_thread_alive (tp->ptid)) - { - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: not switching back to " - "stepped thread, it has vanished\n"); - - delete_thread (tp->ptid); - return 0; - } - if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: switching back to stepped thread\n"); - reset_ecs (ecs, tp); - switch_to_thread (tp->ptid); + if (keep_going_stepped_thread (stepping_thread)) + { + prepare_to_wait (ecs); + return 1; + } + } + } - stop_pc = regcache_read_pc (get_thread_regcache (tp->ptid)); - frame = get_current_frame (); - gdbarch = get_frame_arch (frame); + return 0; +} - /* If the PC of the thread we were trying to single-step has - changed, then that thread has trapped or been signaled, - but the event has not been reported to GDB yet. Re-poll - the target looking for this particular thread's event - (i.e. temporarily enable schedlock) by: +/* Set a previously stepped thread back to stepping. Returns true on + success, false if the resume is not possible (e.g., the thread + vanished). */ + +static int +keep_going_stepped_thread (struct thread_info *tp) +{ + struct frame_info *frame; + struct gdbarch *gdbarch; + struct execution_control_state ecss; + struct execution_control_state *ecs = &ecss; - - setting a break at the current PC - - resuming that particular thread, only (by setting - trap expected) + /* If the stepping thread exited, then don't try to switch back and + resume it, which could fail in several different ways depending + on the target. Instead, just keep going. - This prevents us continuously moving the single-step - breakpoint forward, one instruction at a time, - overstepping. */ + We can find a stepping dead thread in the thread list in two + cases: - if (stop_pc != tp->prev_pc) - { - ptid_t resume_ptid; + - The target supports thread exit events, and when the target + tries to delete the thread from the thread list, inferior_ptid + pointed at the exiting thread. In such case, calling + delete_thread does not really remove the thread from the list; + instead, the thread is left listed, with 'exited' state. - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: expected thread advanced also " - "(%s -> %s)\n", - paddress (target_gdbarch (), tp->prev_pc), - paddress (target_gdbarch (), stop_pc)); - - /* Clear the info of the previous step-over, as it's no - longer valid (if the thread was trying to step over a - breakpoint, it has already succeeded). It's what - keep_going would do too, if we called it. Do this - before trying to insert the sss breakpoint, otherwise - if we were previously trying to step over this exact - address in another thread, the breakpoint is - skipped. */ - clear_step_over_info (); - tp->control.trap_expected = 0; - - insert_single_step_breakpoint (get_frame_arch (frame), - get_frame_address_space (frame), - stop_pc); - - resume_ptid = user_visible_resume_ptid (tp->control.stepping_command); - do_target_resume (resume_ptid, 0, GDB_SIGNAL_0); - prepare_to_wait (ecs); - } - else - { - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: expected thread still " - "hasn't advanced\n"); - keep_going_pass (ecs); - } + - The target's debug interface does not support thread exit + events, and so we have no idea whatsoever if the previously + stepping thread is still alive. For that reason, we need to + synchronously query the target now. */ - return 1; - } + if (is_exited (tp->ptid) + || !target_thread_alive (tp->ptid)) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: not resuming previously " + "stepped thread, it has vanished\n"); + + delete_thread (tp->ptid); + return 0; } - return 0; + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: resuming previously stepped thread\n"); + + reset_ecs (ecs, tp); + switch_to_thread (tp->ptid); + + stop_pc = regcache_read_pc (get_thread_regcache (tp->ptid)); + frame = get_current_frame (); + gdbarch = get_frame_arch (frame); + + /* If the PC of the thread we were trying to single-step has + changed, then that thread has trapped or been signaled, but the + event has not been reported to GDB yet. Re-poll the target + looking for this particular thread's event (i.e. temporarily + enable schedlock) by: + + - setting a break at the current PC + - resuming that particular thread, only (by setting trap + expected) + + This prevents us continuously moving the single-step breakpoint + forward, one instruction at a time, overstepping. */ + + if (stop_pc != tp->prev_pc) + { + ptid_t resume_ptid; + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: expected thread advanced also (%s -> %s)\n", + paddress (target_gdbarch (), tp->prev_pc), + paddress (target_gdbarch (), stop_pc)); + + /* Clear the info of the previous step-over, as it's no longer + valid (if the thread was trying to step over a breakpoint, it + has already succeeded). It's what keep_going would do too, + if we called it. Do this before trying to insert the sss + breakpoint, otherwise if we were previously trying to step + over this exact address in another thread, the breakpoint is + skipped. */ + clear_step_over_info (); + tp->control.trap_expected = 0; + + insert_single_step_breakpoint (get_frame_arch (frame), + get_frame_address_space (frame), + stop_pc); + + resume_ptid = user_visible_resume_ptid (tp->control.stepping_command); + do_target_resume (resume_ptid, 0, GDB_SIGNAL_0); + } + else + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: expected thread still hasn't advanced\n"); + + keep_going_pass (ecs); + } + return 1; } /* Is thread TP in the middle of single-stepping? */