[lldb] [Process/FreeBSD] Report fork/vfork events to LLGS

Differential Revision: https://reviews.llvm.org/D100547
This commit is contained in:
Michał Górny 2021-04-15 13:17:00 +02:00
parent 4b9be5ac08
commit 65f2a75737
5 changed files with 99 additions and 28 deletions

View File

@ -863,7 +863,7 @@ def checkForkVForkSupport():
from lldbsuite.test import lldbplatformutil
platform = lldbplatformutil.getPlatform()
if platform not in ["linux"]:
if platform not in ["freebsd", "linux"]:
configuration.skip_categories.append("fork")

View File

@ -128,13 +128,19 @@ NativeProcessFreeBSD::Factory::Attach(
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 @@ void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) {
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<void *>(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<lldb::tid_t>(info.pl_lwpid))
@ -271,6 +264,26 @@ void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) {
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<void *>(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 @@ bool NativeProcessFreeBSD::SupportHardwareSingleStepping() const {
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 @@ void NativeProcessFreeBSD::MonitorClone(::pid_t child_pid) {
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<void *>(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<NativeProcessFreeBSD> 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<NativeThreadFreeBSD &>(*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<void *>(1), 0);
if (pt_error.Fail()) {
LLDB_LOG_ERROR(log, pt_error.ToError(),
"unable to resume parent process {1}: {0}", GetID());
SetState(StateType::eStateInvalid);
}
}
}

View File

@ -39,6 +39,8 @@ public:
llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
Attach(lldb::pid_t pid, NativeDelegate &native_delegate,
MainLoop &mainloop) const override;
Extension GetSupportedExtensions() const override;
};
// NativeProcessProtocol Interface
@ -96,6 +98,7 @@ protected:
private:
MainLoop::SignalHandleUP m_sigchld_handle;
ArchSpec m_arch;
MainLoop& m_main_loop;
LazyBool m_supports_mem_region = eLazyBoolCalculate;
std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
@ -113,7 +116,8 @@ private:
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();

View File

@ -130,6 +130,30 @@ void NativeThreadFreeBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
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();

View File

@ -59,6 +59,9 @@ private:
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();