[lldb] [Process] Watch for fork/vfork notifications

Watch for fork(2)/vfork(2) (also fork/vfork-style clone(2) on Linux)
notifications and explicitly detach the forked child process, and add
initial tests for these cases.  The code covers FreeBSD, Linux
and NetBSD process plugins.  There is no new user-visible functionality
provided -- this change lays foundations over subsequent work on fork
support.

Differential Revision: https://reviews.llvm.org/D98822
This commit is contained in:
Michał Górny
2021-03-12 09:02:36 +01:00
parent bcb8ef2d5a
commit a345419ee0
21 changed files with 451 additions and 52 deletions

View File

@@ -256,6 +256,24 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
SetState(StateType::eStateStopped, true);
return;
}
case TRAP_CHLD: {
ptrace_state_t pst;
Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));
if (error.Fail()) {
SetState(StateType::eStateInvalid);
return;
}
if (pst.pe_report_event == PTRACE_VFORK_DONE) {
Status error =
PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
if (error.Fail())
SetState(StateType::eStateInvalid);
return;
} else
MonitorClone(pst.pe_other_pid);
return;
}
case TRAP_LWP: {
ptrace_state_t pst;
Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));
@@ -510,7 +528,7 @@ Status NativeProcessNetBSD::Detach() {
if (GetID() == LLDB_INVALID_PROCESS_ID)
return error;
return PtraceWrapper(PT_DETACH, GetID());
return PtraceWrapper(PT_DETACH, GetID(), reinterpret_cast<void *>(1));
}
Status NativeProcessNetBSD::Signal(int signo) {
@@ -738,17 +756,17 @@ Status NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
void NativeProcessNetBSD::SigchldHandler() {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
// Process all pending waitpid notifications.
int status;
::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status,
WALLSIG | WNOHANG);
if (wait_pid == 0)
return; // We are done.
return;
if (wait_pid == -1) {
Status error(errno, eErrorTypePOSIX);
LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
return;
}
WaitStatus wait_status = WaitStatus::Decode(status);
@@ -936,8 +954,9 @@ Status NativeProcessNetBSD::SetupTrace() {
PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events));
if (status.Fail())
return status;
// TODO: PTRACE_FORK | PTRACE_VFORK | PTRACE_POSIX_SPAWN?
events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
// TODO: PTRACE_POSIX_SPAWN?
events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT | PTRACE_FORK |
PTRACE_VFORK | PTRACE_VFORK_DONE;
status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events));
if (status.Fail())
return status;
@@ -974,3 +993,39 @@ Status NativeProcessNetBSD::ReinitializeThreads() {
return error;
}
void NativeProcessNetBSD::MonitorClone(::pid_t child_pid) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
LLDB_LOG(log, "clone, child_pid={0}", child_pid);
int status;
::pid_t wait_pid =
llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0);
if (wait_pid != child_pid) {
LLDB_LOG(log,
"waiting for pid {0} failed. Assuming the pid has "
"disappeared in the meantime",
child_pid);
return;
}
if (WIFEXITED(status)) {
LLDB_LOG(log,
"waiting for pid {0} returned an 'exited' event. Not "
"tracking it.",
child_pid);
return;
}
MainLoop unused_loop;
NativeProcessNetBSD child_process{static_cast<::pid_t>(child_pid),
m_terminal_fd, *m_delegates[0], 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, std::move(pt_error.ToError()),
"unable to resume parent process {1}: {0}", GetID());
SetState(StateType::eStateInvalid);
}
}