From patchwork Tue Feb 28 18:18:37 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Baldwin X-Patchwork-Id: 65802 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 01C43385843D for ; Tue, 28 Feb 2023 18:19:33 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail.baldwin.cx (bigwig.baldwin.cx [IPv6:2607:f138:0:13::2]) by sourceware.org (Postfix) with ESMTPS id 9EFC23858CDB for ; Tue, 28 Feb 2023 18:19:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9EFC23858CDB Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=FreeBSD.org Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=FreeBSD.org Received: from gimli.baldwin.net (c-98-35-126-114.hsd1.ca.comcast.net [98.35.126.114]) by mail.baldwin.cx (Postfix) with ESMTPSA id 0D3A31A84E29 for ; Tue, 28 Feb 2023 13:18:54 -0500 (EST) From: John Baldwin To: gdb-patches@sourceware.org Subject: [PATCH 1/9] fbsd-nat: Add missing spaces. Date: Tue, 28 Feb 2023 10:18:37 -0800 Message-Id: <20230228181845.99936-2-jhb@FreeBSD.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230228181845.99936-1-jhb@FreeBSD.org> References: <20230228181845.99936-1-jhb@FreeBSD.org> MIME-Version: 1.0 X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.6.4 (mail.baldwin.cx [0.0.0.0]); Tue, 28 Feb 2023 13:18:55 -0500 (EST) X-Virus-Scanned: clamav-milter 0.103.1 at mail.baldwin.cx X-Virus-Status: Clean X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00, FORGED_SPF_HELO, GIT_PATCH_0, KAM_DMARC_STATUS, KHOP_HELO_FCRDNS, SPF_HELO_PASS, SPF_SOFTFAIL, 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.29 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 Sender: "Gdb-patches" No functional change, just style fixes. --- gdb/fbsd-nat.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c index 27d2fe45092..4e48bfa1590 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -852,23 +852,23 @@ fbsd_enable_proc_events (pid_t pid) #ifdef PT_GET_EVENT_MASK int events; - if (ptrace (PT_GET_EVENT_MASK, pid, (PTRACE_TYPE_ARG3)&events, + if (ptrace (PT_GET_EVENT_MASK, pid, (PTRACE_TYPE_ARG3) &events, sizeof (events)) == -1) perror_with_name (("ptrace (PT_GET_EVENT_MASK)")); events |= PTRACE_FORK | PTRACE_LWP; #ifdef PTRACE_VFORK events |= PTRACE_VFORK; #endif - if (ptrace (PT_SET_EVENT_MASK, pid, (PTRACE_TYPE_ARG3)&events, + if (ptrace (PT_SET_EVENT_MASK, pid, (PTRACE_TYPE_ARG3) &events, sizeof (events)) == -1) perror_with_name (("ptrace (PT_SET_EVENT_MASK)")); #else #ifdef TDP_RFPPWAIT - if (ptrace (PT_FOLLOW_FORK, pid, (PTRACE_TYPE_ARG3)0, 1) == -1) + if (ptrace (PT_FOLLOW_FORK, pid, (PTRACE_TYPE_ARG3) 0, 1) == -1) perror_with_name (("ptrace (PT_FOLLOW_FORK)")); #endif #ifdef PT_LWP_EVENTS - if (ptrace (PT_LWP_EVENTS, pid, (PTRACE_TYPE_ARG3)0, 1) == -1) + if (ptrace (PT_LWP_EVENTS, pid, (PTRACE_TYPE_ARG3) 0, 1) == -1) perror_with_name (("ptrace (PT_LWP_EVENTS)")); #endif #endif @@ -1369,7 +1369,7 @@ fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus, gdb_assert (pid == child); - if (ptrace (PT_LWPINFO, child, (caddr_t)&pl, sizeof pl) == -1) + if (ptrace (PT_LWPINFO, child, (caddr_t) &pl, sizeof pl) == -1) perror_with_name (("ptrace (PT_LWPINFO)")); gdb_assert (pl.pl_flags & PL_FLAG_CHILD); @@ -1489,7 +1489,7 @@ fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, event loop keeps polling until no event is returned. */ if (is_async_p () && ((ourstatus->kind () != TARGET_WAITKIND_IGNORE - && ourstatus->kind() != TARGET_WAITKIND_NO_RESUMED) + && ourstatus->kind () != TARGET_WAITKIND_NO_RESUMED) || ptid != minus_one_ptid)) async_file_mark (); @@ -1607,7 +1607,7 @@ fbsd_nat_target::follow_fork (inferior *child_inf, ptid_t child_ptid, /* Breakpoints have already been detached from the child by infrun.c. */ - if (ptrace (PT_DETACH, child_pid, (PTRACE_TYPE_ARG3)1, 0) == -1) + if (ptrace (PT_DETACH, child_pid, (PTRACE_TYPE_ARG3) 1, 0) == -1) perror_with_name (("ptrace (PT_DETACH)")); #ifndef PTRACE_VFORK @@ -1740,7 +1740,7 @@ fbsd_nat_target::fetch_register_set (struct regcache *regcache, int regnum, if (regnum == -1 || (regnum >= regbase && regcache_map_supplies (map, regnum - regbase, - regcache->arch(), size))) + regcache->arch (), size))) { if (ptrace (fetch_op, pid, (PTRACE_TYPE_ARG3) regs, 0) == -1) perror_with_name (_("Couldn't get registers")); @@ -1765,7 +1765,7 @@ fbsd_nat_target::store_register_set (struct regcache *regcache, int regnum, if (regnum == -1 || (regnum >= regbase && regcache_map_supplies (map, regnum - regbase, - regcache->arch(), size))) + regcache->arch (), size))) { if (ptrace (fetch_op, pid, (PTRACE_TYPE_ARG3) regs, 0) == -1) perror_with_name (_("Couldn't get registers")); @@ -1807,7 +1807,7 @@ fbsd_nat_target::fetch_regset (struct regcache *regcache, int regnum, int note, if (regnum == -1 || (regnum >= regbase && regcache_map_supplies (map, regnum - regbase, - regcache->arch(), size))) + regcache->arch (), size))) { struct iovec iov; @@ -1833,7 +1833,7 @@ fbsd_nat_target::store_regset (struct regcache *regcache, int regnum, int note, if (regnum == -1 || (regnum >= regbase && regcache_map_supplies (map, regnum - regbase, - regcache->arch(), size))) + regcache->arch (), size))) { struct iovec iov; From patchwork Tue Feb 28 18:18:38 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Baldwin X-Patchwork-Id: 65799 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 47E123857835 for ; Tue, 28 Feb 2023 18:19:15 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail.baldwin.cx (bigwig.baldwin.cx [IPv6:2607:f138:0:13::2]) by sourceware.org (Postfix) with ESMTPS id A1D4E3858C83 for ; Tue, 28 Feb 2023 18:19:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A1D4E3858C83 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=FreeBSD.org Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=FreeBSD.org Received: from gimli.baldwin.net (c-98-35-126-114.hsd1.ca.comcast.net [98.35.126.114]) by mail.baldwin.cx (Postfix) with ESMTPSA id 9DDEC1A84E2E for ; Tue, 28 Feb 2023 13:18:55 -0500 (EST) From: John Baldwin To: gdb-patches@sourceware.org Subject: [PATCH 2/9] fbsd-nat: Avoid a direct write to target_waitstatus::kind. Date: Tue, 28 Feb 2023 10:18:38 -0800 Message-Id: <20230228181845.99936-3-jhb@FreeBSD.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230228181845.99936-1-jhb@FreeBSD.org> References: <20230228181845.99936-1-jhb@FreeBSD.org> MIME-Version: 1.0 X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.6.4 (mail.baldwin.cx [0.0.0.0]); Tue, 28 Feb 2023 13:18:55 -0500 (EST) X-Virus-Scanned: clamav-milter 0.103.1 at mail.baldwin.cx X-Virus-Status: Clean X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00, FORGED_SPF_HELO, GIT_PATCH_0, KAM_DMARC_STATUS, KHOP_HELO_FCRDNS, SPF_HELO_PASS, SPF_SOFTFAIL, 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.29 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 Sender: "Gdb-patches" This is in #ifdef'd code for a workaround for FreeBSD versions older than 11.1 which is why it wasn't caught earlier. --- gdb/fbsd-nat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c index 4e48bfa1590..2f5b512fb33 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -1261,7 +1261,7 @@ fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus, wptid = fbsd_next_vfork_done (); if (wptid != null_ptid) { - ourstatus->kind = TARGET_WAITKIND_VFORK_DONE; + ourstatus->set_vfork_done (); return wptid; } #endif From patchwork Tue Feb 28 18:18:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Baldwin X-Patchwork-Id: 65800 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 081AF38515FF for ; Tue, 28 Feb 2023 18:19:17 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail.baldwin.cx (bigwig.baldwin.cx [66.216.25.90]) by sourceware.org (Postfix) with ESMTPS id 601953858D33 for ; Tue, 28 Feb 2023 18:19:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 601953858D33 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=FreeBSD.org Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=FreeBSD.org Received: from gimli.baldwin.net (c-98-35-126-114.hsd1.ca.comcast.net [98.35.126.114]) by mail.baldwin.cx (Postfix) with ESMTPSA id 38A7B1A84E30 for ; Tue, 28 Feb 2023 13:18:56 -0500 (EST) From: John Baldwin To: gdb-patches@sourceware.org Subject: [PATCH 3/9] fbsd-nat: Use correct constant for target_waitstatus::sig. Date: Tue, 28 Feb 2023 10:18:39 -0800 Message-Id: <20230228181845.99936-4-jhb@FreeBSD.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230228181845.99936-1-jhb@FreeBSD.org> References: <20230228181845.99936-1-jhb@FreeBSD.org> MIME-Version: 1.0 X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.6.4 (mail.baldwin.cx [0.0.0.0]); Tue, 28 Feb 2023 13:18:56 -0500 (EST) X-Virus-Scanned: clamav-milter 0.103.1 at mail.baldwin.cx X-Virus-Status: Clean X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00, FORGED_SPF_HELO, GIT_PATCH_0, KAM_DMARC_STATUS, KHOP_HELO_FCRDNS, SPF_HELO_PASS, SPF_SOFTFAIL, 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.29 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 Sender: "Gdb-patches" Use GDB_SIGNAL_TRAP instead of SIGTRAP. This is a no-op since the value of SIGTRAP on FreeBSD matches the value of GDB_SIGNAL_TRAP, but it is more correct. --- gdb/fbsd-nat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c index 2f5b512fb33..04d67fc5278 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -1439,7 +1439,7 @@ fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus, SIGTRAP, so only treat SIGTRAP events as system call entry/exit events. */ if (pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX) - && ourstatus->sig () == SIGTRAP) + && ourstatus->sig () == GDB_SIGNAL_TRAP) { #ifdef HAVE_STRUCT_PTRACE_LWPINFO_PL_SYSCALL_CODE if (catch_syscall_enabled ()) From patchwork Tue Feb 28 18:18:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Baldwin X-Patchwork-Id: 65806 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 4A32D3858296 for ; Tue, 28 Feb 2023 18:19:51 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail.baldwin.cx (bigwig.baldwin.cx [IPv6:2607:f138:0:13::2]) by sourceware.org (Postfix) with ESMTPS id 9C3D13858D3C for ; Tue, 28 Feb 2023 18:19:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9C3D13858D3C Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=FreeBSD.org Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=FreeBSD.org Received: from gimli.baldwin.net (c-98-35-126-114.hsd1.ca.comcast.net [98.35.126.114]) by mail.baldwin.cx (Postfix) with ESMTPSA id C68461A84E32 for ; Tue, 28 Feb 2023 13:18:56 -0500 (EST) From: John Baldwin To: gdb-patches@sourceware.org Subject: [PATCH 4/9] fbsd-nat: Add a list of pending events. Date: Tue, 28 Feb 2023 10:18:40 -0800 Message-Id: <20230228181845.99936-5-jhb@FreeBSD.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230228181845.99936-1-jhb@FreeBSD.org> References: <20230228181845.99936-1-jhb@FreeBSD.org> MIME-Version: 1.0 X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.6.4 (mail.baldwin.cx [0.0.0.0]); Tue, 28 Feb 2023 13:18:57 -0500 (EST) X-Virus-Scanned: clamav-milter 0.103.1 at mail.baldwin.cx X-Virus-Status: Clean X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, FORGED_SPF_HELO, GIT_PATCH_0, KAM_DMARC_STATUS, KHOP_HELO_FCRDNS, SPF_HELO_PASS, SPF_SOFTFAIL, 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.29 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 Sender: "Gdb-patches" The pending_events list stores a queue of deferred events that might be reported by the next call to the target's wait method. The set of events that are eligible is filtered by the ptid passed to resume. For now this just replaces the list of vfork_done events. A subsequent commit will reuse this to store other events. --- gdb/fbsd-nat.c | 146 ++++++++++++++++++++++++++++++++----------------- gdb/fbsd-nat.h | 2 + 2 files changed, 98 insertions(+), 50 deletions(-) diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c index 04d67fc5278..ca278b871ef 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -54,6 +54,66 @@ #define PT_SETREGSET 43 /* Set a target register set */ #endif +/* Filter for ptid's allowed to report events from wait. Normally set + in resume, but also reset to minus_one_ptid in create_inferior and + attach. */ + +static ptid_t resume_ptid; + +/* If an event is triggered asynchronously (fake vfork_done events) or + occurs when the core is not expecting it, a pending event is + created. This event is then returned by a future call to the + target wait method. */ + +struct pending_event +{ + pending_event (const ptid_t &_ptid, const target_waitstatus &_status) : + ptid(_ptid), status(_status) {} + + ptid_t ptid; + target_waitstatus status; +}; + +static std::list pending_events; + +/* Add a new pending event to the list. */ + +static void +add_pending_event (const ptid_t &ptid, const target_waitstatus &status) +{ + pending_events.emplace_back (ptid, status); +} + +/* Return true if there is a pending event matching FILTER. */ + +static bool +have_pending_event (ptid_t filter) +{ + for (const pending_event &event : pending_events) + if (event.ptid.matches (filter)) + return true; + return false; +} + +/* Helper method called by the target wait method. Returns true if + there is a pending event matching resume_ptid. If there is a + matching event, PTID and *STATUS contain the event details, and the + event is removed from the pending list. */ + +static bool +take_pending_event (ptid_t &ptid, target_waitstatus *status) +{ + for (auto it = pending_events.begin (); it != pending_events.end (); it++) + if (it->ptid.matches (resume_ptid)) + { + ptid = it->ptid; + *status = it->status; + pending_events.erase (it); + return true; + } + return false; +} + /* Return the name of a file that can be opened to get the symbols for the child process identified by PID. */ @@ -1061,47 +1121,20 @@ fbsd_is_child_pending (pid_t pid) } #ifndef PTRACE_VFORK -static std::forward_list fbsd_pending_vfork_done; - /* Record a pending vfork done event. */ static void fbsd_add_vfork_done (ptid_t pid) { - fbsd_pending_vfork_done.push_front (pid); + target_waitstatus status; + status.set_vfork_done (); + add_pending_event (ptid, status); /* If we're in async mode, need to tell the event loop there's something here to process. */ if (target_is_async_p ()) async_file_mark (); } - -/* Check for a pending vfork done event for a specific PID. */ - -static int -fbsd_is_vfork_done_pending (pid_t pid) -{ - for (auto it = fbsd_pending_vfork_done.begin (); - it != fbsd_pending_vfork_done.end (); it++) - if (it->pid () == pid) - return 1; - return 0; -} - -/* Check for a pending vfork done event. If one is found, remove it - from the list and return the PTID. */ - -static ptid_t -fbsd_next_vfork_done (void) -{ - if (!fbsd_pending_vfork_done.empty ()) - { - ptid_t ptid = fbsd_pending_vfork_done.front (); - fbsd_pending_vfork_done.pop_front (); - return ptid; - } - return null_ptid; -} #endif #endif @@ -1110,21 +1143,18 @@ fbsd_next_vfork_done (void) void fbsd_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signo) { -#if defined(TDP_RFPPWAIT) && !defined(PTRACE_VFORK) - pid_t pid; - - /* Don't PT_CONTINUE a process which has a pending vfork done event. */ - if (minus_one_ptid == ptid) - pid = inferior_ptid.pid (); - else - pid = ptid.pid (); - if (fbsd_is_vfork_done_pending (pid)) - return; -#endif - fbsd_nat_debug_printf ("[%s], step %d, signo %d (%s)", target_pid_to_str (ptid).c_str (), step, signo, gdb_signal_to_name (signo)); + + /* Don't PT_CONTINUE a thread or process which has a pending event. */ + resume_ptid = ptid; + if (have_pending_event (ptid)) + { + fbsd_nat_debug_printf ("found pending event"); + return; + } + if (ptid.lwp_p ()) { /* If ptid is a specific LWP, suspend all other LWPs in the process. */ @@ -1257,14 +1287,6 @@ fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus, while (1) { -#ifndef PTRACE_VFORK - wptid = fbsd_next_vfork_done (); - if (wptid != null_ptid) - { - ourstatus->set_vfork_done (); - return wptid; - } -#endif wptid = inf_ptrace_target::wait (ptid, ourstatus, target_options); if (ourstatus->kind () == TARGET_WAITKIND_STOPPED) { @@ -1478,6 +1500,16 @@ fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, fbsd_nat_debug_printf ("[%s], [%s]", target_pid_to_str (ptid).c_str (), target_options_to_string (target_options).c_str ()); + /* If there is a valid pending event, return it. */ + if (take_pending_event (wptid, ourstatus)) + { + fbsd_nat_debug_printf ("returning pending event [%s], [%s]", + target_pid_to_str (wptid).c_str (), + ourstatus->to_string ().c_str ()); + gdb_assert (wptid.matches (ptid)); + return wptid; + } + /* Ensure any subsequent events trigger a new event in the loop. */ if (is_async_p ()) async_file_flush (); @@ -1585,9 +1617,23 @@ fbsd_nat_target::create_inferior (const char *exec_file, (disable_randomization); #endif + /* Expect a wait for the new process. */ + resume_ptid = minus_one_ptid; + fbsd_nat_debug_printf ("setting resume_ptid to [%s]", + target_pid_to_str (resume_ptid).c_str ()); inf_ptrace_target::create_inferior (exec_file, allargs, env, from_tty); } +void +fbsd_nat_target::attach (const char *args, int from_tty) +{ + /* Expect a wait for the new process. */ + resume_ptid = minus_one_ptid; + fbsd_nat_debug_printf ("setting resume_ptid to [%s]", + target_pid_to_str (resume_ptid).c_str ()); + inf_ptrace_target::attach (args, from_tty); +} + #ifdef TDP_RFPPWAIT /* Target hook for follow_fork. On entry and at return inferior_ptid is the ptid of the followed inferior. */ diff --git a/gdb/fbsd-nat.h b/gdb/fbsd-nat.h index a19bceaf5e4..cda150ac465 100644 --- a/gdb/fbsd-nat.h +++ b/gdb/fbsd-nat.h @@ -76,6 +76,8 @@ class fbsd_nat_target : public inf_ptrace_target void create_inferior (const char *, const std::string &, char **, int) override; + void attach (const char *, int) override; + void resume (ptid_t, int, enum gdb_signal) override; ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override; From patchwork Tue Feb 28 18:18:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Baldwin X-Patchwork-Id: 65801 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 D6DF23850209 for ; Tue, 28 Feb 2023 18:19:26 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail.baldwin.cx (bigwig.baldwin.cx [IPv6:2607:f138:0:13::2]) by sourceware.org (Postfix) with ESMTPS id DA0653858C50 for ; Tue, 28 Feb 2023 18:19:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org DA0653858C50 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=FreeBSD.org Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=FreeBSD.org Received: from gimli.baldwin.net (c-98-35-126-114.hsd1.ca.comcast.net [98.35.126.114]) by mail.baldwin.cx (Postfix) with ESMTPSA id 6A5181A84E33 for ; Tue, 28 Feb 2023 13:18:57 -0500 (EST) From: John Baldwin To: gdb-patches@sourceware.org Subject: [PATCH 5/9] fbsd-nat: Defer any ineligible events reported by wait. Date: Tue, 28 Feb 2023 10:18:41 -0800 Message-Id: <20230228181845.99936-6-jhb@FreeBSD.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230228181845.99936-1-jhb@FreeBSD.org> References: <20230228181845.99936-1-jhb@FreeBSD.org> MIME-Version: 1.0 X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.6.4 (mail.baldwin.cx [0.0.0.0]); Tue, 28 Feb 2023 13:18:57 -0500 (EST) X-Virus-Scanned: clamav-milter 0.103.1 at mail.baldwin.cx X-Virus-Status: Clean X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, FORGED_SPF_HELO, GIT_PATCH_0, KAM_DMARC_STATUS, KHOP_HELO_FCRDNS, SPF_HELO_PASS, SPF_SOFTFAIL, 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.29 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 Sender: "Gdb-patches" If wait_1 finds an event for a thread or process that does not match the set of threads and processes previously resumed, defer the event. If the event is for a specific thread, suspend the thread and continue the associated process before waiting for another event. One specific example of such an event is if a thread is created while another thread in the same process hits a breakpoint. If the second thread's event is reported first, the target resume method does not yet "know" about the new thread and will not suspend it via PT_SUSPEND. When wait is called, it will probably return the event from the first thread before the result of the step from second thread. This is the case reported in PR 21497. --- gdb/fbsd-nat.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c index ca278b871ef..3f7278c6ea0 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -1514,7 +1514,39 @@ fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, if (is_async_p ()) async_file_flush (); - wptid = wait_1 (ptid, ourstatus, target_options); + while (1) + { + wptid = wait_1 (ptid, ourstatus, target_options); + + /* If no event was found, just return. */ + if (ourstatus->kind () == TARGET_WAITKIND_IGNORE + || ourstatus->kind () == TARGET_WAITKIND_NO_RESUMED) + break; + + /* If an event is reported for a thread or process while + stepping some other thread, suspend the thread reporting the + event and defer the event until it can be reported to the + core. */ + if (!wptid.matches (resume_ptid)) + { + add_pending_event (wptid, *ourstatus); + fbsd_nat_debug_printf ("deferring event [%s], [%s]", + target_pid_to_str (wptid).c_str (), + ourstatus->to_string ().c_str ()); + if (wptid.pid () == resume_ptid.pid ()) + { + fbsd_nat_debug_printf ("suspending thread [%s]", + target_pid_to_str (wptid).c_str ()); + if (ptrace (PT_SUSPEND, wptid.lwp (), NULL, 0) == -1) + perror_with_name (("ptrace (PT_SUSPEND)")); + if (ptrace (PT_CONTINUE, wptid.pid (), (caddr_t) 1, 0) == -1) + perror_with_name (("ptrace (PT_CONTINUE)")); + } + continue; + } + + break; + } /* If we are in async mode and found an event, there may still be another event pending. Trigger the event pipe so that that the From patchwork Tue Feb 28 18:18:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Baldwin X-Patchwork-Id: 65807 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 26F723850221 for ; Tue, 28 Feb 2023 18:19:58 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail.baldwin.cx (bigwig.baldwin.cx [IPv6:2607:f138:0:13::2]) by sourceware.org (Postfix) with ESMTPS id DA3293858C53 for ; Tue, 28 Feb 2023 18:19:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org DA3293858C53 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=FreeBSD.org Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=FreeBSD.org Received: from gimli.baldwin.net (c-98-35-126-114.hsd1.ca.comcast.net [98.35.126.114]) by mail.baldwin.cx (Postfix) with ESMTPSA id 0A0511A84E34 for ; Tue, 28 Feb 2023 13:18:57 -0500 (EST) From: John Baldwin To: gdb-patches@sourceware.org Subject: [PATCH 6/9] fbsd-nat: Fix resuming and waiting with multiple processes. Date: Tue, 28 Feb 2023 10:18:42 -0800 Message-Id: <20230228181845.99936-7-jhb@FreeBSD.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230228181845.99936-1-jhb@FreeBSD.org> References: <20230228181845.99936-1-jhb@FreeBSD.org> MIME-Version: 1.0 X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.6.4 (mail.baldwin.cx [0.0.0.0]); Tue, 28 Feb 2023 13:18:58 -0500 (EST) X-Virus-Scanned: clamav-milter 0.103.1 at mail.baldwin.cx X-Virus-Status: Clean X-Spam-Status: No, score=-12.0 required=5.0 tests=BAYES_00, FORGED_SPF_HELO, GIT_PATCH_0, KAM_DMARC_STATUS, KHOP_HELO_FCRDNS, SPF_HELO_PASS, SPF_SOFTFAIL, 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.29 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 Sender: "Gdb-patches" I did not fully understand the requirements of multiple process support when I enabled it previously and several parts were broken. In particular, the resume method was only resuming a single process, and wait was not stopping other processes when reporting an event. To support multiple running inferiors, add a new per-inferior structure which trackes the number of existing and running LWPs for each process. The structure also stores a ptid_t describing the set of LWPs currently resumed for each process. For the resume method, iterate over all non-exited inferiors resuming each process matching the passed in ptid rather than only resuming the current inferior's process for a wildcard ptid. If a resumed process has a pending event, don't actually resume the process, but other matching processes without a pending event are still resumed in case the later call to the wait method requests an event from one of the processes without a pending event. For the wait method, stop other running processes before returning an event to the core. When stopping a process, first check to see if an event is already pending. If it is, queue the event to be reported later. If not, send a SIGSTOP to the process and wait for it to stop. If the event reported by the wait is not for the SIGSTOP, queue the event and remember to ignore a future SIGSTOP event for the process. Note that, unlike the Linux native target, entire processes are stopped rather than individual LWPs. In FreeBSD one can only wait on processes (via pid), not for an event from a specific thread. Other changes in this commit handle bookkeeping for the per-inferior data such as purging the data in the mourn_inferior method and migrating the data to the new inferior in the follow_exec method. The per-inferior data is created in the attach, create_inferior, and follow_fork methods. --- gdb/fbsd-nat.c | 403 +++++++++++++++++++++++++++++++++++++------------ gdb/fbsd-nat.h | 8 + 2 files changed, 317 insertions(+), 94 deletions(-) diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c index 3f7278c6ea0..14b31ddd86e 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -54,11 +54,26 @@ #define PT_SETREGSET 43 /* Set a target register set */ #endif -/* Filter for ptid's allowed to report events from wait. Normally set - in resume, but also reset to minus_one_ptid in create_inferior and - attach. */ +/* Information stored about each inferior. */ -static ptid_t resume_ptid; +struct fbsd_inferior_info +{ + /* Filter for resumed LWPs which can report events from wait. */ + ptid_t resumed_lwps = null_ptid; + + /* Number of LWPs this process contains. */ + unsigned int num_lwps = 0; + + /* Number of LWPs currently running. */ + unsigned int running_lwps = 0; + + /* Have a pending SIGSTOP event that needs to be discarded. */ + bool pending_sigstop = false; +}; + +/* Per-inferior data key. */ + +static const registry::key fbsd_inferior_data; /* If an event is triggered asynchronously (fake vfork_done events) or occurs when the core is not expecting it, a pending event is @@ -95,21 +110,27 @@ have_pending_event (ptid_t filter) return false; } -/* Helper method called by the target wait method. Returns true if - there is a pending event matching resume_ptid. If there is a - matching event, PTID and *STATUS contain the event details, and the - event is removed from the pending list. */ +/* Returns true if there is a pending event for a resumed process + matching FILTER. If there is a matching event, PTID and *STATUS + contain the event details, and the event is removed from the + pending list. */ static bool -take_pending_event (ptid_t &ptid, target_waitstatus *status) +take_pending_event (fbsd_nat_target *target, ptid_t filter, ptid_t &ptid, + target_waitstatus *status) { for (auto it = pending_events.begin (); it != pending_events.end (); it++) - if (it->ptid.matches (resume_ptid)) + if (it->ptid.matches (filter)) { - ptid = it->ptid; - *status = it->status; - pending_events.erase (it); - return true; + inferior *inf = find_inferior_ptid (target, it->ptid); + fbsd_inferior_info *info = fbsd_inferior_data.get (inf); + if (it->ptid.matches (info->resumed_lwps)) + { + ptid = it->ptid; + *status = it->status; + pending_events.erase (it); + return true; + } } return false; } @@ -799,6 +820,8 @@ show_fbsd_nat_debug (struct ui_file *file, int from_tty, #define fbsd_nat_debug_printf(fmt, ...) \ debug_prefixed_printf_cond (debug_fbsd_nat, "fbsd-nat", fmt, ##__VA_ARGS__) +#define fbsd_nat_debug_start_end(fmt, ...) \ + scoped_debug_start_end (debug_fbsd_nat, "fbsd-nat", fmt, ##__VA_ARGS__) /* FreeBSD's first thread support was via a "reentrant" version of libc @@ -956,6 +979,9 @@ fbsd_add_threads (fbsd_nat_target *target, pid_t pid) if (nlwps == -1) perror_with_name (("ptrace (PT_GETLWPLIST)")); + inferior *inf = find_inferior_ptid (target, ptid_t (pid)); + fbsd_inferior_info *info = fbsd_inferior_data.get (inf); + gdb_assert (info != nullptr); for (i = 0; i < nlwps; i++) { ptid_t ptid = ptid_t (pid, lwps[i]); @@ -974,8 +1000,14 @@ fbsd_add_threads (fbsd_nat_target *target, pid_t pid) #endif fbsd_lwp_debug_printf ("adding thread for LWP %u", lwps[i]); add_thread (target, ptid); +#ifdef PT_LWP_EVENTS + info->num_lwps++; +#endif } } +#ifndef PT_LWP_EVENTS + info->num_lwps = nlwps; +#endif } /* Implement the "update_thread_list" target_ops method. */ @@ -1138,92 +1170,117 @@ fbsd_add_vfork_done (ptid_t pid) #endif #endif -/* Implement the "resume" target_ops method. */ +/* Resume a single process. */ void -fbsd_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signo) +fbsd_nat_target::resume_one_process (ptid_t ptid, int step, + enum gdb_signal signo) { fbsd_nat_debug_printf ("[%s], step %d, signo %d (%s)", target_pid_to_str (ptid).c_str (), step, signo, gdb_signal_to_name (signo)); + inferior *inf = find_inferior_ptid (this, ptid); + fbsd_inferior_info *info = fbsd_inferior_data.get (inf); + info->resumed_lwps = ptid; + gdb_assert (info->running_lwps == 0); + /* Don't PT_CONTINUE a thread or process which has a pending event. */ - resume_ptid = ptid; if (have_pending_event (ptid)) { fbsd_nat_debug_printf ("found pending event"); return; } - if (ptid.lwp_p ()) + for (thread_info *tp : inf->non_exited_threads ()) { - /* If ptid is a specific LWP, suspend all other LWPs in the process. */ - inferior *inf = find_inferior_ptid (this, ptid); + int request; - for (thread_info *tp : inf->non_exited_threads ()) - { - int request; - - if (tp->ptid.lwp () == ptid.lwp ()) - request = PT_RESUME; - else - request = PT_SUSPEND; - - if (ptrace (request, tp->ptid.lwp (), NULL, 0) == -1) - perror_with_name (request == PT_RESUME ? - ("ptrace (PT_RESUME)") : - ("ptrace (PT_SUSPEND)")); - if (request == PT_RESUME) - low_prepare_to_resume (tp); - } - } - else - { - /* If ptid is a wildcard, resume all matching threads (they won't run - until the process is continued however). */ - for (thread_info *tp : all_non_exited_threads (this, ptid)) + /* If ptid is a specific LWP, suspend all other LWPs in the + process, otherwise resume all LWPs in the process.. */ + if (!ptid.lwp_p() || tp->ptid.lwp () == ptid.lwp ()) { if (ptrace (PT_RESUME, tp->ptid.lwp (), NULL, 0) == -1) perror_with_name (("ptrace (PT_RESUME)")); low_prepare_to_resume (tp); + info->running_lwps++; } + else + { + if (ptrace (PT_SUSPEND, tp->ptid.lwp (), NULL, 0) == -1) + perror_with_name (("ptrace (PT_SUSPEND)")); + } + } + + if (ptid.pid () != inferior_ptid.pid ()) + { + step = 0; + signo = GDB_SIGNAL_0; + gdb_assert (!ptid.lwp_p ()); + } + else + { ptid = inferior_ptid; - } - #if __FreeBSD_version < 1200052 - /* When multiple threads within a process wish to report STOPPED - events from wait(), the kernel picks one thread event as the - thread event to report. The chosen thread event is retrieved via - PT_LWPINFO by passing the process ID as the request pid. If - multiple events are pending, then the subsequent wait() after - resuming a process will report another STOPPED event after - resuming the process to handle the next thread event and so on. + /* When multiple threads within a process wish to report STOPPED + events from wait(), the kernel picks one thread event as the + thread event to report. The chosen thread event is retrieved + via PT_LWPINFO by passing the process ID as the request pid. + If multiple events are pending, then the subsequent wait() + after resuming a process will report another STOPPED event + after resuming the process to handle the next thread event + and so on. - A single thread event is cleared as a side effect of resuming the - process with PT_CONTINUE, PT_STEP, etc. In older kernels, - however, the request pid was used to select which thread's event - was cleared rather than always clearing the event that was just - reported. To avoid clearing the event of the wrong LWP, always - pass the process ID instead of an LWP ID to PT_CONTINUE or - PT_SYSCALL. + A single thread event is cleared as a side effect of resuming + the process with PT_CONTINUE, PT_STEP, etc. In older + kernels, however, the request pid was used to select which + thread's event was cleared rather than always clearing the + event that was just reported. To avoid clearing the event of + the wrong LWP, always pass the process ID instead of an LWP + ID to PT_CONTINUE or PT_SYSCALL. - In the case of stepping, the process ID cannot be used with - PT_STEP since it would step the thread that reported an event - which may not be the thread indicated by PTID. For stepping, use - PT_SETSTEP to enable stepping on the desired thread before - resuming the process via PT_CONTINUE instead of using - PT_STEP. */ - if (step) - { - if (ptrace (PT_SETSTEP, get_ptrace_pid (ptid), NULL, 0) == -1) - perror_with_name (("ptrace (PT_SETSTEP)")); - step = 0; - } - ptid = ptid_t (ptid.pid ()); + In the case of stepping, the process ID cannot be used with + PT_STEP since it would step the thread that reported an event + which may not be the thread indicated by PTID. For stepping, + use PT_SETSTEP to enable stepping on the desired thread + before resuming the process via PT_CONTINUE instead of using + PT_STEP. */ + if (step) + { + if (ptrace (PT_SETSTEP, get_ptrace_pid (ptid), NULL, 0) == -1) + perror_with_name (("ptrace (PT_SETSTEP)")); + step = 0; + } + ptid = ptid_t (ptid.pid ()); #endif + } + inf_ptrace_target::resume (ptid, step, signo); } +/* Implement the "resume" target_ops method. */ + +void +fbsd_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signo) +{ + fbsd_nat_debug_start_end ("[%s], step %d, signo %d (%s)", + target_pid_to_str (ptid).c_str (), step, signo, + gdb_signal_to_name (signo)); + + gdb_assert (inferior_ptid.matches (ptid)); + gdb_assert (!ptid.tid_p ()); + + if (ptid == minus_one_ptid) + { + for (inferior *inf : all_non_exited_inferiors (this)) + resume_one_process (ptid_t (inf->pid), step, signo); + } + else + { + resume_one_process (ptid, step, signo); + } +} + #ifdef USE_SIGTRAP_SIGINFO /* Handle breakpoint and trace traps reported via SIGTRAP. If the trap was a breakpoint or trace trap that should be reported to the @@ -1291,10 +1348,7 @@ fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus, if (ourstatus->kind () == TARGET_WAITKIND_STOPPED) { struct ptrace_lwpinfo pl; - pid_t pid; - int status; - - pid = wptid.pid (); + pid_t pid = wptid.pid (); if (ptrace (PT_LWPINFO, pid, (caddr_t) &pl, sizeof pl) == -1) perror_with_name (("ptrace (PT_LWPINFO)")); @@ -1310,6 +1364,13 @@ fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus, pl.pl_siginfo.si_code); } + /* There may not be an inferior for this pid if this is a + PL_FLAG_CHILD event. */ + inferior *inf = find_inferior_ptid (this, wptid); + fbsd_inferior_info *info = inf == nullptr ? nullptr : + fbsd_inferior_data.get (inf); + gdb_assert (info != NULL || pl.pl_flags & PL_FLAG_CHILD); + #ifdef PT_LWP_EVENTS if (pl.pl_flags & PL_FLAG_EXITED) { @@ -1327,6 +1388,20 @@ fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus, target_pid_to_str (wptid).c_str ()); low_delete_thread (thr); delete_thread (thr); + info->num_lwps--; + + /* If this LWP was the only resumed LWP from the + process, report an event to the core. */ + if (wptid == info->resumed_lwps) + { + ourstatus->set_spurious (); + return wptid; + } + + /* During process exit LWPs that were not resumed + will report exit events. */ + if (wptid.matches (info->resumed_lwps)) + info->running_lwps--; } if (ptrace (PT_CONTINUE, pid, (caddr_t) 1, 0) == -1) perror_with_name (("ptrace (PT_CONTINUE)")); @@ -1359,6 +1434,10 @@ fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus, fbsd_lwp_debug_printf ("adding thread for LWP %u", pl.pl_lwpid); add_thread (this, wptid); + info->num_lwps++; + + if (wptid.matches(info->resumed_lwps)) + info->running_lwps++; } ourstatus->set_spurious (); return wptid; @@ -1385,6 +1464,8 @@ fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus, child_ptid = fbsd_is_child_pending (child); if (child_ptid == null_ptid) { + int status; + pid = waitpid (child, &status, 0); if (pid == -1) perror_with_name (("waitpid")); @@ -1486,11 +1567,99 @@ fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus, perror_with_name (("ptrace (PT_CONTINUE)")); continue; } + + /* If this is a pending SIGSTOP event from an earlier call + to stop_process, discard the event and wait for another + event. */ + if (ourstatus->sig () == GDB_SIGNAL_STOP && info->pending_sigstop) + { + fbsd_nat_debug_printf ("ignoring SIGSTOP for pid %u", pid); + info->pending_sigstop = false; + if (ptrace (PT_CONTINUE, pid, (caddr_t) 1, 0) == -1) + perror_with_name (("ptrace (PT_CONTINUE)")); + continue; + } } + else + fbsd_nat_debug_printf ("event [%s], [%s]", + target_pid_to_str (wptid).c_str (), + ourstatus->to_string ().c_str ()); return wptid; } } +/* Stop a given process. If the process is already stopped, record + its pending event instead. */ + +void +fbsd_nat_target::stop_process (inferior *inf) +{ + fbsd_inferior_info *info = fbsd_inferior_data.get (inf); + gdb_assert (info != nullptr); + + info->resumed_lwps = null_ptid; + if (info->running_lwps == 0) + return; + + ptid_t ptid (inf->pid); + target_waitstatus status; + ptid_t wptid = wait_1 (ptid, &status, TARGET_WNOHANG); + + if (wptid != minus_one_ptid) + { + /* Save the current event as a pending event. */ + add_pending_event (wptid, status); + info->running_lwps = 0; + return; + } + + /* If a SIGSTOP is already pending, don't send a new one, but tell + wait_1 to report a SIGSTOP. */ + if (info->pending_sigstop) + { + fbsd_nat_debug_printf ("waiting for existing pending SIGSTOP for %u", + inf->pid); + info->pending_sigstop = false; + } + else + { + /* Ignore errors from kill as process exit might race with kill. */ + fbsd_nat_debug_printf ("killing %u with SIGSTOP", inf->pid); + ::kill (inf->pid, SIGSTOP); + } + + /* Wait for SIGSTOP (or some other event) to be reported. */ + wptid = wait_1 (ptid, &status, 0); + + switch (status.kind ()) + { + case TARGET_WAITKIND_EXITED: + case TARGET_WAITKIND_SIGNALLED: + /* If the process has exited, we aren't going to get an + event for the SIGSTOP. Save the current event and + return. */ + add_pending_event (wptid, status); + break; + case TARGET_WAITKIND_STOPPED: + /* If this is the SIGSTOP event, discard it and return + leaving the process stopped. */ + if (status.sig () == GDB_SIGNAL_STOP) + break; + + /* FALLTHROUGH */ + default: + /* Some other event has occurred. Save the current + event. */ + add_pending_event (wptid, status); + + /* Ignore the next SIGSTOP for this process. */ + fbsd_nat_debug_printf ("ignoring next SIGSTOP for %u", inf->pid); + info->pending_sigstop = true; + break; + } + info->running_lwps = 0; +} + ptid_t fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, target_wait_flags target_options) @@ -1501,8 +1670,12 @@ fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, target_options_to_string (target_options).c_str ()); /* If there is a valid pending event, return it. */ - if (take_pending_event (wptid, ourstatus)) + if (take_pending_event (this, ptid, wptid, ourstatus)) { + /* Stop any other inferiors currently running. */ + for (inferior *inf : all_non_exited_inferiors (this)) + stop_process (inf); + fbsd_nat_debug_printf ("returning pending event [%s], [%s]", target_pid_to_str (wptid).c_str (), ourstatus->to_string ().c_str ()); @@ -1523,28 +1696,38 @@ fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, || ourstatus->kind () == TARGET_WAITKIND_NO_RESUMED) break; + inferior *inf = find_inferior_ptid (this, wptid); + gdb_assert (inf != nullptr); + fbsd_inferior_info *info = fbsd_inferior_data.get (inf); + gdb_assert (info != nullptr); + gdb_assert (info->resumed_lwps != null_ptid); + gdb_assert (info->running_lwps > 0); + /* If an event is reported for a thread or process while stepping some other thread, suspend the thread reporting the event and defer the event until it can be reported to the core. */ - if (!wptid.matches (resume_ptid)) + if (!wptid.matches (info->resumed_lwps)) { add_pending_event (wptid, *ourstatus); fbsd_nat_debug_printf ("deferring event [%s], [%s]", target_pid_to_str (wptid).c_str (), ourstatus->to_string ().c_str ()); - if (wptid.pid () == resume_ptid.pid ()) - { - fbsd_nat_debug_printf ("suspending thread [%s]", - target_pid_to_str (wptid).c_str ()); - if (ptrace (PT_SUSPEND, wptid.lwp (), NULL, 0) == -1) - perror_with_name (("ptrace (PT_SUSPEND)")); - if (ptrace (PT_CONTINUE, wptid.pid (), (caddr_t) 1, 0) == -1) - perror_with_name (("ptrace (PT_CONTINUE)")); - } + if (ptrace (PT_SUSPEND, wptid.lwp (), NULL, 0) == -1) + perror_with_name (("ptrace (PT_SUSPEND)")); + if (ptrace (PT_CONTINUE, wptid.pid (), (caddr_t) 1, 0) == -1) + perror_with_name (("ptrace (PT_CONTINUE)")); continue; } + /* This process is no longer running. */ + info->resumed_lwps = null_ptid; + info->running_lwps = 0; + + /* Stop any other inferiors currently running. */ + for (inferior *inf : all_non_exited_inferiors (this)) + stop_process (inf); + break; } @@ -1649,23 +1832,49 @@ fbsd_nat_target::create_inferior (const char *exec_file, (disable_randomization); #endif - /* Expect a wait for the new process. */ - resume_ptid = minus_one_ptid; - fbsd_nat_debug_printf ("setting resume_ptid to [%s]", - target_pid_to_str (resume_ptid).c_str ()); + fbsd_inferior_info *info = fbsd_inferior_data.emplace (current_inferior ()); + info->resumed_lwps = minus_one_ptid; + info->num_lwps = 1; + info->running_lwps = 1; inf_ptrace_target::create_inferior (exec_file, allargs, env, from_tty); } void fbsd_nat_target::attach (const char *args, int from_tty) { - /* Expect a wait for the new process. */ - resume_ptid = minus_one_ptid; - fbsd_nat_debug_printf ("setting resume_ptid to [%s]", - target_pid_to_str (resume_ptid).c_str ()); + fbsd_inferior_info *info = fbsd_inferior_data.emplace (current_inferior ()); + info->resumed_lwps = minus_one_ptid; + info->num_lwps = 1; + info->running_lwps = 1; inf_ptrace_target::attach (args, from_tty); } +void +fbsd_nat_target::mourn_inferior () +{ + inferior *inf = current_inferior (); + gdb_assert (!have_pending_event (ptid_t (inf->pid))); + fbsd_inferior_data.clear (inf); + inf_ptrace_target::mourn_inferior (); +} + +void +fbsd_nat_target::follow_exec (inferior *follow_inf, ptid_t ptid, + const char *execd_pathname) +{ + inferior *orig_inf = current_inferior (); + + inf_ptrace_target::follow_exec (follow_inf, ptid, execd_pathname); + + if (orig_inf != follow_inf) + { + /* Migrate the inferior info to the new inferior. */ + fbsd_inferior_info *info = fbsd_inferior_data.get (orig_inf); + fbsd_inferior_data.set (orig_inf, nullptr); + fbsd_inferior_data.set (follow_inf, info); + } +} + #ifdef TDP_RFPPWAIT /* Target hook for follow_fork. On entry and at return inferior_ptid is the ptid of the followed inferior. */ @@ -1678,6 +1887,12 @@ fbsd_nat_target::follow_fork (inferior *child_inf, ptid_t child_ptid, inf_ptrace_target::follow_fork (child_inf, child_ptid, fork_kind, follow_child, detach_fork); + if (child_inf != nullptr) + { + fbsd_inferior_info *info = fbsd_inferior_data.emplace (child_inf); + info->num_lwps = 1; + } + if (!follow_child && detach_fork) { pid_t child_pid = child_ptid.pid (); diff --git a/gdb/fbsd-nat.h b/gdb/fbsd-nat.h index cda150ac465..97856573962 100644 --- a/gdb/fbsd-nat.h +++ b/gdb/fbsd-nat.h @@ -78,6 +78,8 @@ class fbsd_nat_target : public inf_ptrace_target void attach (const char *, int) override; + void mourn_inferior () override; + void resume (ptid_t, int, enum gdb_signal) override; ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override; @@ -89,6 +91,8 @@ class fbsd_nat_target : public inf_ptrace_target bool stopped_by_sw_breakpoint () override; #endif + void follow_exec (inferior *, ptid_t, const char *) override; + #ifdef TDP_RFPPWAIT void follow_fork (inferior *, ptid_t, target_waitkind, bool, bool) override; @@ -132,6 +136,10 @@ class fbsd_nat_target : public inf_ptrace_target private: ptid_t wait_1 (ptid_t, struct target_waitstatus *, target_wait_flags); + void resume_one_process (ptid_t, int, enum gdb_signal); + + void stop_process (inferior *); + /* Helper routines for use in fetch_registers and store_registers in subclasses. These routines fetch and store a single set of registers described by REGSET. The REGSET's 'regmap' field must From patchwork Tue Feb 28 18:18:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Baldwin X-Patchwork-Id: 65804 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 11C14384DD31 for ; Tue, 28 Feb 2023 18:19:49 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail.baldwin.cx (bigwig.baldwin.cx [IPv6:2607:f138:0:13::2]) by sourceware.org (Postfix) with ESMTPS id 2FC233858416 for ; Tue, 28 Feb 2023 18:19:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2FC233858416 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=FreeBSD.org Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=FreeBSD.org Received: from gimli.baldwin.net (c-98-35-126-114.hsd1.ca.comcast.net [98.35.126.114]) by mail.baldwin.cx (Postfix) with ESMTPSA id ADA1C1A84E36 for ; Tue, 28 Feb 2023 13:18:58 -0500 (EST) From: John Baldwin To: gdb-patches@sourceware.org Subject: [PATCH 7/9] fbsd-nat: Fix several issues with detaching. Date: Tue, 28 Feb 2023 10:18:43 -0800 Message-Id: <20230228181845.99936-8-jhb@FreeBSD.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230228181845.99936-1-jhb@FreeBSD.org> References: <20230228181845.99936-1-jhb@FreeBSD.org> MIME-Version: 1.0 X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.6.4 (mail.baldwin.cx [0.0.0.0]); Tue, 28 Feb 2023 13:18:58 -0500 (EST) X-Virus-Scanned: clamav-milter 0.103.1 at mail.baldwin.cx X-Virus-Status: Clean X-Spam-Status: No, score=-12.0 required=5.0 tests=BAYES_00, FORGED_SPF_HELO, GIT_PATCH_0, KAM_DMARC_STATUS, KHOP_HELO_FCRDNS, SPF_HELO_PASS, SPF_SOFTFAIL, 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.29 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 Sender: "Gdb-patches" - Detach from any child processes implicitly attached to by the kernel due to fork following that have not yet been processed by GDB's core. - Delete breakpoints before detaching. inf-ptrace::detach does not do this (somewhat surprisingly), so add an override to remove breakpoints from a process before detaching from it. This also requires explicitly draining any pending SIGTRAP events for software breakpoints before detaching. In particular, threads may need their PC adjusted due to the software breakpoint before being resumed after detach. On more modern systems using the si_code from SIGTRAP to identify software breakpoint traps, the PC is adjusted in ::wait_1 as a side effect of parsing the event. To support older kernels, ::detach fixes up the PC for any SIGTRAP stop whose potential new PC matches an existing software breakpoint. --- gdb/fbsd-nat.c | 260 +++++++++++++++++++++++++++++++++++++++++++++++++ gdb/fbsd-nat.h | 2 + 2 files changed, 262 insertions(+) diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c index 14b31ddd86e..e3d83cbf908 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -1849,6 +1849,266 @@ fbsd_nat_target::attach (const char *args, int from_tty) inf_ptrace_target::attach (args, from_tty); } +/* If this thread has a pending fork event, there is a child process + GDB is attached to that the core of GDB doesn't know about. + Detach from it. */ + +static void +detach_fork_children (thread_info *tp) +{ + /* Check in thread_info::pending_waitstatus. */ + if (tp->has_pending_waitstatus ()) + { + const target_waitstatus &ws = tp->pending_waitstatus (); + + if (ws.kind () == TARGET_WAITKIND_VFORKED + || ws.kind () == TARGET_WAITKIND_FORKED) + { + pid_t pid = ws.child_ptid ().pid (); + fbsd_nat_debug_printf ("detaching from child %d", pid); + (void) ptrace (PT_DETACH, pid, (caddr_t) 1, 0); + } + } + + /* Check in thread_info::pending_follow. */ + if (tp->pending_follow.kind () == TARGET_WAITKIND_VFORKED + || tp->pending_follow.kind () == TARGET_WAITKIND_FORKED) + { + pid_t pid = tp->pending_follow.child_ptid ().pid (); + fbsd_nat_debug_printf ("detaching from child %d", pid); + (void) ptrace (PT_DETACH, pid, (caddr_t) 1, 0); + } +} + +/* Detach from any child processes associated with pending fork events + for a stopped process. Returns true if the process has terminated + and false if it is still alive. */ + +static bool +detach_fork_children (fbsd_nat_target *target, inferior *inf) +{ + /* Detach any child processes associated with pending fork events in + threads belonging to this process. */ + for (thread_info *tp : inf->non_exited_threads ()) + detach_fork_children (tp); + + /* Unwind state associated with any pending events. Reset + info->resumed_lwps so that take_pending_event will harvest + events. */ + fbsd_inferior_info *info = fbsd_inferior_data.get (inf); + ptid_t ptid = ptid_t (inf->pid); + info->resumed_lwps = ptid; + + ptid_t wptid; + target_waitstatus ws; + while (take_pending_event (target, ptid, wptid, &ws)) + { + switch (ws.kind ()) + { + case TARGET_WAITKIND_EXITED: + case TARGET_WAITKIND_SIGNALLED: + return true; + case TARGET_WAITKIND_FORKED: + case TARGET_WAITKIND_VFORKED: + { + pid_t pid = ws.child_ptid ().pid (); + fbsd_nat_debug_printf ("detaching from child %d", pid); + (void) ptrace (PT_DETACH, pid, (caddr_t) 1, 0); + } + break; + } + } + return false; +} + +/* Scan all of the threads for a stopped process invoking the supplied + callback on the ptrace_lwpinfo object for threads other than the + thread which reported the current stop. The callback can return + true to terminate the iteration early. This function returns true + if the callback returned true, otherwise it returns false. */ + +typedef bool (ptrace_event_ftype) (const struct ptrace_lwpinfo &pl); + +static bool +iterate_other_ptrace_events (pid_t pid, + gdb::function_view callback) +{ + /* Fetch the LWP ID of the thread that just reported the last stop + and ignore that LWP in the following loop. */ + ptrace_lwpinfo pl; + if (ptrace (PT_LWPINFO, pid, (caddr_t) &pl, sizeof (pl)) != 0) + perror_with_name (("ptrace (PT_LWPINFO)")); + lwpid_t lwpid = pl.pl_lwpid; + + int nlwps = ptrace (PT_GETNUMLWPS, pid, NULL, 0); + if (nlwps == -1) + perror_with_name (("ptrace (PT_GETLWPLIST)")); + if (nlwps == 1) + return false; + + gdb::unique_xmalloc_ptr lwps (XCNEWVEC (lwpid_t, nlwps)); + + nlwps = ptrace (PT_GETLWPLIST, pid, (caddr_t) lwps.get (), nlwps); + if (nlwps == -1) + perror_with_name (("ptrace (PT_GETLWPLIST)")); + + for (int i = 0; i < nlwps; i++) + { + if (lwps[i] == lwpid) + continue; + + if (ptrace (PT_LWPINFO, lwps[i], (caddr_t) &pl, sizeof (pl)) != 0) + perror_with_name (("ptrace (PT_LWPINFO)")); + + if (callback (pl)) + return true; + } + return false; +} + +/* True if there are any stopped threads with an interesting event. */ + +static bool +pending_ptrace_events (inferior *inf) +{ + auto lambda = [] (const struct ptrace_lwpinfo &pl) + { +#ifdef PT_LWP_EVENTS + if (pl.pl_flags == PL_FLAG_BORN) + return true; +#endif +#ifdef TDP_RFPPWAIT + if (pl.pl_flags & PL_FLAG_FORKED) + return true; +#endif + if (pl.pl_event == PL_EVENT_SIGNAL) + { + if ((pl.pl_flags & PL_FLAG_SI) == 0) + { + /* Not sure which signal, assume it matters. */ + return true; + } + if (pl.pl_siginfo.si_signo == SIGTRAP) + return true; + } + return false; + }; + return iterate_other_ptrace_events (inf->pid, + gdb::make_function_view (lambda)); +} + +void +fbsd_nat_target::detach (inferior *inf, int from_tty) +{ + fbsd_nat_debug_start_end ("pid %d", inf->pid); + + stop_process (inf); + + remove_breakpoints_inf (inf); + + if (detach_fork_children (this, inf)) { + /* No need to detach now. */ + target_announce_detach (from_tty); + + detach_success (inf); + return; + } + + /* If there are any pending events (SIGSTOP from stop_process or a + breakpoint hit that needs a PC fixup), drain events until the + process can be safely detached. */ + fbsd_inferior_info *info = fbsd_inferior_data.get (inf); + ptid_t ptid = ptid_t (inf->pid); + if (info->pending_sigstop || pending_ptrace_events (inf)) + { + bool pending_sigstop = info->pending_sigstop; + int sig = 0; + + if (pending_sigstop) + fbsd_nat_debug_printf ("waiting for SIGSTOP"); + + /* Force wait_1 to report the SIGSTOP instead of swallowing it. */ + info->pending_sigstop = false; + + /* Report event for all threads from wait_1. */ + info->resumed_lwps = ptid; + + do + { + if (ptrace (PT_CONTINUE, inf->pid, (caddr_t) 1, sig) != 0) + perror_with_name (("ptrace(PT_CONTINUE)")); + + target_waitstatus ws; + ptid_t wptid = wait_1 (ptid, &ws, 0); + + switch (ws.kind ()) + { + case TARGET_WAITKIND_EXITED: + case TARGET_WAITKIND_SIGNALLED: + /* No need to detach now. */ + target_announce_detach (from_tty); + + detach_success (inf); + return; + case TARGET_WAITKIND_FORKED: + case TARGET_WAITKIND_VFORKED: + { + pid_t pid = ws.child_ptid ().pid (); + fbsd_nat_debug_printf ("detaching from child %d", pid); + (void) ptrace (PT_DETACH, pid, (caddr_t) 1, 0); + sig = 0; + } + break; + case TARGET_WAITKIND_STOPPED: + sig = gdb_signal_to_host (ws.sig ()); + switch (sig) + { + case SIGSTOP: + if (pending_sigstop) + { + sig = 0; + pending_sigstop = false; + } + break; + case SIGTRAP: +#ifndef USE_SIGTRAP_SIGINFO + { + /* Update PC from software breakpoint hit. */ + struct regcache *regcache = get_thread_regcache (this, wptid); + struct gdbarch *gdbarch = regcache->arch (); + int decr_pc = gdbarch_decr_pc_after_break (gdbarch); + + if (decr_pc != 0) + { + CORE_ADDR pc; + + pc = regcache_read_pc (regcache); + if (breakpoint_inserted_here_p (regcache->aspace (), + pc - decr_pc)) + { + fbsd_nat_debug_printf ("adjusted PC for LWP %ld", + wptid.lwp ()); + regcache_write_pc (regcache, pc - decr_pc); + } + } + } +#endif + sig = 0; + break; + } + } + } + while (pending_sigstop || pending_ptrace_events (inf)); + } + + target_announce_detach (from_tty); + + if (ptrace (PT_DETACH, inf->pid, (caddr_t) 1, 0) == -1) + perror_with_name (("ptrace (PT_DETACH)")); + + detach_success (inf); +} + void fbsd_nat_target::mourn_inferior () { diff --git a/gdb/fbsd-nat.h b/gdb/fbsd-nat.h index 97856573962..3dc22ce1cca 100644 --- a/gdb/fbsd-nat.h +++ b/gdb/fbsd-nat.h @@ -78,6 +78,8 @@ class fbsd_nat_target : public inf_ptrace_target void attach (const char *, int) override; + void detach (inferior *, int) override; + void mourn_inferior () override; void resume (ptid_t, int, enum gdb_signal) override; From patchwork Tue Feb 28 18:18:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Baldwin X-Patchwork-Id: 65803 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 AB8D33850425 for ; Tue, 28 Feb 2023 18:19:38 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail.baldwin.cx (bigwig.baldwin.cx [IPv6:2607:f138:0:13::2]) by sourceware.org (Postfix) with ESMTPS id 3C7FD3858C54 for ; Tue, 28 Feb 2023 18:19:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3C7FD3858C54 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=FreeBSD.org Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=FreeBSD.org Received: from gimli.baldwin.net (c-98-35-126-114.hsd1.ca.comcast.net [98.35.126.114]) by mail.baldwin.cx (Postfix) with ESMTPSA id 461231A84E38 for ; Tue, 28 Feb 2023 13:18:59 -0500 (EST) From: John Baldwin To: gdb-patches@sourceware.org Subject: [PATCH 8/9] fbsd-nat: Fix thread_alive against a running thread. Date: Tue, 28 Feb 2023 10:18:44 -0800 Message-Id: <20230228181845.99936-9-jhb@FreeBSD.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230228181845.99936-1-jhb@FreeBSD.org> References: <20230228181845.99936-1-jhb@FreeBSD.org> MIME-Version: 1.0 X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.6.4 (mail.baldwin.cx [0.0.0.0]); Tue, 28 Feb 2023 13:18:59 -0500 (EST) X-Virus-Scanned: clamav-milter 0.103.1 at mail.baldwin.cx X-Virus-Status: Clean X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, FORGED_SPF_HELO, GIT_PATCH_0, KAM_DMARC_STATUS, KHOP_HELO_FCRDNS, SPF_HELO_PASS, SPF_SOFTFAIL, 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.29 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 Sender: "Gdb-patches" FreeBSD's ptrace fails requests with EBUSY against a running process. Report that the thread is alive instead of dead if ptrace fails with EBUSY. This fixes an internal error in the gdb.threads/detach-step-over.exp test where one process was detached while a thread in a second process was being stepped. The core incorrectly assumed the stepping thread had vanished and discarded the pending stepping state. When the thread later reported a SIGTRAP from completing the step, this triggered an assertion. --- gdb/fbsd-nat.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c index e3d83cbf908..32dd482ec3c 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -861,7 +861,13 @@ fbsd_nat_target::thread_alive (ptid_t ptid) if (ptrace (PT_LWPINFO, ptid.lwp (), (caddr_t) &pl, sizeof pl) == -1) - return false; + { + /* EBUSY means the associated process is running which means + the LWP does exist and belongs to a running process. */ + if (errno == EBUSY) + return true; + return false; + } #ifdef PL_FLAG_EXITED if (pl.pl_flags & PL_FLAG_EXITED) return false; From patchwork Tue Feb 28 18:18:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Baldwin X-Patchwork-Id: 65805 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 8FCCE384840B for ; Tue, 28 Feb 2023 18:19:50 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail.baldwin.cx (bigwig.baldwin.cx [IPv6:2607:f138:0:13::2]) by sourceware.org (Postfix) with ESMTPS id AB5A33858C78 for ; Tue, 28 Feb 2023 18:19:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org AB5A33858C78 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=FreeBSD.org Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=FreeBSD.org Received: from gimli.baldwin.net (c-98-35-126-114.hsd1.ca.comcast.net [98.35.126.114]) by mail.baldwin.cx (Postfix) with ESMTPSA id DF7921A84E3A for ; Tue, 28 Feb 2023 13:18:59 -0500 (EST) From: John Baldwin To: gdb-patches@sourceware.org Subject: [PATCH 9/9] fbsd-nat: Stop a process if it is running before killing it. Date: Tue, 28 Feb 2023 10:18:45 -0800 Message-Id: <20230228181845.99936-10-jhb@FreeBSD.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230228181845.99936-1-jhb@FreeBSD.org> References: <20230228181845.99936-1-jhb@FreeBSD.org> MIME-Version: 1.0 X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.6.4 (mail.baldwin.cx [0.0.0.0]); Tue, 28 Feb 2023 13:19:00 -0500 (EST) X-Virus-Scanned: clamav-milter 0.103.1 at mail.baldwin.cx X-Virus-Status: Clean X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, FORGED_SPF_HELO, GIT_PATCH_0, KAM_DMARC_STATUS, KHOP_HELO_FCRDNS, SPF_HELO_PASS, SPF_SOFTFAIL, 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.29 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 Sender: "Gdb-patches" In addition, detach from any child processes implicitly attached to by the kernel due to fork following that have not yet been processed by GDB's core. --- gdb/fbsd-nat.c | 93 +++++++++++++++++++++++++++++++++++++++++--------- gdb/fbsd-nat.h | 2 ++ 2 files changed, 78 insertions(+), 17 deletions(-) diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c index 32dd482ec3c..42c69875b0f 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -1158,6 +1158,31 @@ fbsd_is_child_pending (pid_t pid) return null_ptid; } +/* Wait for a child of a fork to report its stop. Returns the PTID of + the new child process. */ + +static ptid_t +fbsd_wait_for_fork_child (pid_t pid) +{ + ptid_t ptid = fbsd_is_child_pending (pid); + if (ptid != null_ptid) + return ptid; + + int status; + pid_t wpid = waitpid (pid, &status, 0); + if (wpid == -1) + perror_with_name (("waitpid")); + + gdb_assert (wpid == pid); + + struct ptrace_lwpinfo pl; + if (ptrace (PT_LWPINFO, wpid, (caddr_t) &pl, sizeof pl) == -1) + perror_with_name (("ptrace (PT_LWPINFO)")); + + gdb_assert (pl.pl_flags & PL_FLAG_CHILD); + return ptid_t (wpid, pl.pl_lwpid); +} + #ifndef PTRACE_VFORK /* Record a pending vfork done event. */ @@ -1467,23 +1492,7 @@ fbsd_nat_target::wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus, #endif /* Make sure the other end of the fork is stopped too. */ - child_ptid = fbsd_is_child_pending (child); - if (child_ptid == null_ptid) - { - int status; - - pid = waitpid (child, &status, 0); - if (pid == -1) - perror_with_name (("waitpid")); - - gdb_assert (pid == child); - - if (ptrace (PT_LWPINFO, child, (caddr_t) &pl, sizeof pl) == -1) - perror_with_name (("ptrace (PT_LWPINFO)")); - - gdb_assert (pl.pl_flags & PL_FLAG_CHILD); - child_ptid = ptid_t (child, pl.pl_lwpid); - } + child_ptid = fbsd_wait_for_fork_child (child); /* Enable additional events on the child process. */ fbsd_enable_proc_events (child_ptid.pid ()); @@ -2115,6 +2124,56 @@ fbsd_nat_target::detach (inferior *inf, int from_tty) detach_success (inf); } +/* Implement the "kill" target method. */ + +void +fbsd_nat_target::kill () +{ + pid_t pid = inferior_ptid.pid (); + if (pid == 0) + return; + + inferior *inf = current_inferior (); + stop_process (inf); + + if (detach_fork_children (this, inf)) { + /* No need to kill now. */ + target_mourn_inferior (inferior_ptid); + + return; + } + +#ifdef TDP_RFPPWAIT + /* If there are any threads that have forked a new child but not yet + reported it because other threads reported events first, detach + from the children before killing the parent. */ + auto lambda = [] (const struct ptrace_lwpinfo &pl) + { + if (pl.pl_flags & PL_FLAG_FORKED) + { + pid_t child = pl.pl_child_pid; + + /* If the child hasn't reported its stop yet, wait for it to + stop. */ + fbsd_wait_for_fork_child (child); + + /* Detach from the child. */ + (void) ptrace (PT_DETACH, child, (caddr_t) 1, 0); + } + return false; + }; + iterate_other_ptrace_events (pid, gdb::make_function_view (lambda)); +#endif + + if (ptrace (PT_KILL, pid, NULL, 0) == -1) + perror_with_name (("ptrace (PT_KILL)")); + + int status; + waitpid (pid, &status, 0); + + target_mourn_inferior (inferior_ptid); +} + void fbsd_nat_target::mourn_inferior () { diff --git a/gdb/fbsd-nat.h b/gdb/fbsd-nat.h index 3dc22ce1cca..8096c53bc03 100644 --- a/gdb/fbsd-nat.h +++ b/gdb/fbsd-nat.h @@ -80,6 +80,8 @@ class fbsd_nat_target : public inf_ptrace_target void detach (inferior *, int) override; + void kill () override; + void mourn_inferior () override; void resume (ptid_t, int, enum gdb_signal) override;