Index: lldb/packages/Python/lldbsuite/test/dotest.py =================================================================== --- lldb/packages/Python/lldbsuite/test/dotest.py +++ lldb/packages/Python/lldbsuite/test/dotest.py @@ -863,7 +863,7 @@ from lldbsuite.test import lldbplatformutil platform = lldbplatformutil.getPlatform() - if platform not in ["linux"]: + if platform not in ["freebsd", "linux"]: configuration.skip_categories.append("fork") Index: lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h =================================================================== --- lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h +++ lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h @@ -39,6 +39,8 @@ llvm::Expected> Attach(lldb::pid_t pid, NativeDelegate &native_delegate, MainLoop &mainloop) const override; + + Extension GetSupportedExtensions() const override; }; // NativeProcessProtocol Interface @@ -96,6 +98,7 @@ private: MainLoop::SignalHandleUP m_sigchld_handle; ArchSpec m_arch; + MainLoop& m_main_loop; LazyBool m_supports_mem_region = eLazyBoolCalculate; std::vector> m_mem_region_cache; @@ -113,7 +116,8 @@ void MonitorSIGSTOP(lldb::pid_t pid); void MonitorSIGTRAP(lldb::pid_t pid); void MonitorSignal(lldb::pid_t pid, int signal); - void MonitorClone(::pid_t child_pid); + void MonitorClone(::pid_t child_pid, bool is_vfork, + NativeThreadFreeBSD &parent_thread); Status PopulateMemoryRegionCache(); void SigchldHandler(); Index: lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp =================================================================== --- lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp +++ lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp @@ -128,13 +128,19 @@ return std::move(process_up); } +NativeProcessFreeBSD::Extension +NativeProcessFreeBSD::Factory::GetSupportedExtensions() const { + return Extension::multiprocess | Extension::fork | Extension::vfork; +} + // Public Instance Methods NativeProcessFreeBSD::NativeProcessFreeBSD(::pid_t pid, int terminal_fd, NativeDelegate &delegate, const ArchSpec &arch, MainLoop &mainloop) - : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch) { + : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch), + m_main_loop(mainloop) { if (m_terminal_fd != -1) { Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); assert(status.Success()); @@ -247,19 +253,6 @@ return; } - if (info.pl_flags & PL_FLAG_FORKED) { - MonitorClone(info.pl_child_pid); - return; - } - - if (info.pl_flags & PL_FLAG_VFORK_DONE) { - Status error = - PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast(1), 0); - if (error.Fail()) - SetState(StateType::eStateInvalid); - return; - } - if (info.pl_lwpid > 0) { for (const auto &t : m_threads) { if (t->GetID() == static_cast(info.pl_lwpid)) @@ -271,6 +264,26 @@ info.pl_lwpid); } + if (info.pl_flags & PL_FLAG_FORKED) { + assert(thread); + MonitorClone(info.pl_child_pid, info.pl_flags & PL_FLAG_VFORKED, *thread); + return; + } + + if (info.pl_flags & PL_FLAG_VFORK_DONE) { + assert(thread); + if ((m_enabled_extensions & Extension::vfork) == Extension::vfork) { + thread->SetStoppedByVForkDone(); + SetState(StateType::eStateStopped, true); + } else { + Status error = + PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast(1), 0); + if (error.Fail()) + SetState(StateType::eStateInvalid); + } + return; + } + if (info.pl_flags & PL_FLAG_SI) { assert(info.pl_siginfo.si_signo == SIGTRAP); LLDB_LOG(log, "SIGTRAP siginfo: si_code = {0}, pid = {1}", @@ -933,7 +946,8 @@ return !m_arch.IsMIPS(); } -void NativeProcessFreeBSD::MonitorClone(::pid_t child_pid) { +void NativeProcessFreeBSD::MonitorClone(::pid_t child_pid, bool is_vfork, + NativeThreadFreeBSD &parent_thread) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); LLDB_LOG(log, "fork, child_pid={0}", child_pid); @@ -955,16 +969,42 @@ return; } - MainLoop unused_loop; - NativeProcessFreeBSD child_process{static_cast<::pid_t>(child_pid), - m_terminal_fd, m_delegate, m_arch, - unused_loop}; - child_process.Detach(); - Status pt_error = - PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast(1), 0); - if (pt_error.Fail()) { - LLDB_LOG_ERROR(log, pt_error.ToError(), - "unable to resume parent process {1}: {0}", GetID()); - SetState(StateType::eStateInvalid); + struct ptrace_lwpinfo info; + const auto siginfo_err = PtraceWrapper(PT_LWPINFO, child_pid, &info, sizeof(info)); + if (siginfo_err.Fail()) { + LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err); + return; + } + assert(info.pl_event == PL_EVENT_SIGNAL); + lldb::tid_t child_tid = info.pl_lwpid; + + std::unique_ptr child_process{ + new NativeProcessFreeBSD(static_cast<::pid_t>(child_pid), m_terminal_fd, + m_delegate, m_arch, m_main_loop)}; + if (!is_vfork) + child_process->m_software_breakpoints = m_software_breakpoints; + + Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork; + if ((m_enabled_extensions & expected_ext) == expected_ext) { + child_process->SetupTrace(); + for (const auto &thread : child_process->m_threads) + static_cast(*thread).SetStoppedBySignal(SIGSTOP); + child_process->SetState(StateType::eStateStopped, false); + + m_delegate.NewSubprocess(this, std::move(child_process)); + if (is_vfork) + parent_thread.SetStoppedByVFork(child_pid, child_tid); + else + parent_thread.SetStoppedByFork(child_pid, child_tid); + SetState(StateType::eStateStopped, true); + } else { + child_process->Detach(); + Status pt_error = + PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast(1), 0); + if (pt_error.Fail()) { + LLDB_LOG_ERROR(log, pt_error.ToError(), + "unable to resume parent process {1}: {0}", GetID()); + SetState(StateType::eStateInvalid); + } } } Index: lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h =================================================================== --- lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h +++ lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h @@ -59,6 +59,9 @@ void SetStoppedByTrace(); void SetStoppedByExec(); void SetStoppedByWatchpoint(uint32_t wp_index); + void SetStoppedByFork(lldb::pid_t child_pid, lldb::tid_t child_tid); + void SetStoppedByVFork(lldb::pid_t child_pid, lldb::tid_t child_tid); + void SetStoppedByVForkDone(); void SetStoppedWithNoReason(); void SetStopped(); void SetRunning(); Index: lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp =================================================================== --- lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp +++ lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp @@ -130,6 +130,30 @@ m_stop_info.details.signal.signo = SIGTRAP; } +void NativeThreadFreeBSD::SetStoppedByFork(lldb::pid_t child_pid, + lldb::tid_t child_tid) { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonFork; + m_stop_info.details.fork.child_pid = child_pid; + m_stop_info.details.fork.child_tid = child_tid; +} + +void NativeThreadFreeBSD::SetStoppedByVFork(lldb::pid_t child_pid, + lldb::tid_t child_tid) { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonVFork; + m_stop_info.details.fork.child_pid = child_pid; + m_stop_info.details.fork.child_tid = child_tid; +} + +void NativeThreadFreeBSD::SetStoppedByVForkDone() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonVForkDone; +} + void NativeThreadFreeBSD::SetStoppedWithNoReason() { SetStopped();