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