Skip to content

Commit a345419

Browse files
committed
[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
1 parent bcb8ef2 commit a345419

21 files changed

+451
-52
lines changed

lldb/include/lldb/Host/linux/Host.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===-- Host.h --------------------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLDB_HOST_LINUX_HOST_H
10+
#define LLDB_HOST_LINUX_HOST_H
11+
12+
#include "lldb/lldb-types.h"
13+
#include "llvm/ADT/Optional.h"
14+
15+
namespace lldb_private {
16+
17+
// Get PID (i.e. the primary thread ID) corresponding to the specified TID.
18+
llvm::Optional<lldb::pid_t> getPIDForTID(lldb::pid_t tid);
19+
20+
} // namespace lldb_private
21+
22+
#endif // #ifndef LLDB_HOST_LINUX_HOST_H

lldb/source/Host/linux/Host.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "lldb/Host/FileSystem.h"
2828
#include "lldb/Host/Host.h"
2929
#include "lldb/Host/HostInfo.h"
30+
#include "lldb/Host/linux/Host.h"
3031
#include "lldb/Host/linux/Support.h"
3132
#include "lldb/Utility/DataExtractor.h"
3233

@@ -53,7 +54,8 @@ class ProcessLaunchInfo;
5354
}
5455

5556
static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
56-
ProcessState &State, ::pid_t &TracerPid) {
57+
ProcessState &State, ::pid_t &TracerPid,
58+
::pid_t &Tgid) {
5759
Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
5860

5961
auto BufferOrError = getProcFile(Pid, "status");
@@ -107,6 +109,9 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
107109
} else if (Line.consume_front("TracerPid:")) {
108110
Line = Line.ltrim();
109111
Line.consumeInteger(10, TracerPid);
112+
} else if (Line.consume_front("Tgid:")) {
113+
Line = Line.ltrim();
114+
Line.consumeInteger(10, Tgid);
110115
}
111116
}
112117
return true;
@@ -204,6 +209,7 @@ static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info) {
204209
static bool GetProcessAndStatInfo(::pid_t pid,
205210
ProcessInstanceInfo &process_info,
206211
ProcessState &State, ::pid_t &tracerpid) {
212+
::pid_t tgid;
207213
tracerpid = 0;
208214
process_info.Clear();
209215

@@ -214,7 +220,7 @@ static bool GetProcessAndStatInfo(::pid_t pid,
214220
GetProcessEnviron(pid, process_info);
215221

216222
// Get User and Group IDs and get tracer pid.
217-
if (!GetStatusInfo(pid, process_info, State, tracerpid))
223+
if (!GetStatusInfo(pid, process_info, State, tracerpid, tgid))
218224
return false;
219225

220226
return true;
@@ -308,3 +314,14 @@ Environment Host::GetEnvironment() { return Environment(environ); }
308314
Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
309315
return Status("unimplemented");
310316
}
317+
318+
llvm::Optional<lldb::pid_t> lldb_private::getPIDForTID(lldb::pid_t tid) {
319+
::pid_t tracerpid, tgid = LLDB_INVALID_PROCESS_ID;
320+
ProcessInstanceInfo process_info;
321+
ProcessState state;
322+
323+
if (!GetStatusInfo(tid, process_info, state, tracerpid, tgid) ||
324+
tgid == LLDB_INVALID_PROCESS_ID)
325+
return llvm::None;
326+
return tgid;
327+
}

lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,19 @@ void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) {
247247
return;
248248
}
249249

250+
if (info.pl_flags & PL_FLAG_FORKED) {
251+
MonitorClone(info.pl_child_pid);
252+
return;
253+
}
254+
255+
if (info.pl_flags & PL_FLAG_VFORK_DONE) {
256+
Status error =
257+
PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
258+
if (error.Fail())
259+
SetState(StateType::eStateInvalid);
260+
return;
261+
}
262+
250263
if (info.pl_lwpid > 0) {
251264
for (const auto &t : m_threads) {
252265
if (t->GetID() == static_cast<lldb::tid_t>(info.pl_lwpid))
@@ -705,17 +718,17 @@ NativeProcessFreeBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
705718

706719
void NativeProcessFreeBSD::SigchldHandler() {
707720
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
708-
// Process all pending waitpid notifications.
709721
int status;
710722
::pid_t wait_pid =
711723
llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WNOHANG);
712724

713725
if (wait_pid == 0)
714-
return; // We are done.
726+
return;
715727

716728
if (wait_pid == -1) {
717729
Status error(errno, eErrorTypePOSIX);
718730
LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
731+
return;
719732
}
720733

721734
WaitStatus wait_status = WaitStatus::Decode(status);
@@ -885,7 +898,7 @@ Status NativeProcessFreeBSD::SetupTrace() {
885898
PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events));
886899
if (status.Fail())
887900
return status;
888-
events |= PTRACE_LWP;
901+
events |= PTRACE_LWP | PTRACE_FORK | PTRACE_VFORK;
889902
status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events));
890903
if (status.Fail())
891904
return status;
@@ -919,3 +932,53 @@ Status NativeProcessFreeBSD::ReinitializeThreads() {
919932
bool NativeProcessFreeBSD::SupportHardwareSingleStepping() const {
920933
return !m_arch.IsMIPS();
921934
}
935+
936+
void NativeProcessFreeBSD::MonitorClone(::pid_t child_pid) {
937+
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
938+
LLDB_LOG(log, "fork, child_pid={0}", child_pid);
939+
940+
int status;
941+
::pid_t wait_pid =
942+
llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0);
943+
if (wait_pid != child_pid) {
944+
LLDB_LOG(log,
945+
"waiting for pid {0} failed. Assuming the pid has "
946+
"disappeared in the meantime",
947+
child_pid);
948+
return;
949+
}
950+
if (WIFEXITED(status)) {
951+
LLDB_LOG(log,
952+
"waiting for pid {0} returned an 'exited' event. Not "
953+
"tracking it.",
954+
child_pid);
955+
return;
956+
}
957+
958+
MainLoop unused_loop;
959+
NativeProcessFreeBSD child_process{static_cast<::pid_t>(child_pid),
960+
m_terminal_fd, *m_delegates[0], m_arch,
961+
unused_loop};
962+
child_process.ReinitializeThreads();
963+
auto *child_thread =
964+
static_cast<NativeThreadFreeBSD *>(child_process.GetCurrentThread());
965+
assert(child_thread);
966+
// new processes inherit dbregs, so we need to clear them
967+
llvm::Error error = child_thread->GetRegisterContext().ClearDBRegs();
968+
if (error) {
969+
LLDB_LOG_ERROR(log, std::move(error),
970+
"failed to clear dbregs in forked process {1}: {0}",
971+
child_pid);
972+
SetState(StateType::eStateInvalid);
973+
return;
974+
}
975+
976+
child_process.Detach();
977+
Status pt_error =
978+
PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), 0);
979+
if (pt_error.Fail()) {
980+
LLDB_LOG_ERROR(log, pt_error.ToError(),
981+
"unable to resume parent process {1}: {0}", GetID());
982+
SetState(StateType::eStateInvalid);
983+
}
984+
}

lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ class NativeProcessFreeBSD : public NativeProcessELF,
113113
void MonitorSIGSTOP(lldb::pid_t pid);
114114
void MonitorSIGTRAP(lldb::pid_t pid);
115115
void MonitorSignal(lldb::pid_t pid, int signal);
116+
void MonitorClone(::pid_t child_pid);
116117

117118
Status PopulateMemoryRegionCache();
118119
void SigchldHandler();

lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class NativeRegisterContextFreeBSD
3232
virtual llvm::Error
3333
CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) = 0;
3434

35+
virtual llvm::Error ClearDBRegs() { return llvm::Error::success(); }
36+
3537
protected:
3638
virtual NativeProcessFreeBSD &GetProcess();
3739
virtual ::pid_t GetProcessPid();

lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,4 +285,19 @@ NativeRegisterContextFreeBSD_arm64::WriteHardwareDebugRegs(DREGType) {
285285
#endif
286286
}
287287

288+
llvm::Error NativeRegisterContextFreeBSD_arm64::ClearDBRegs() {
289+
#ifdef LLDB_HAS_FREEBSD_WATCHPOINT
290+
if (llvm::Error error = ReadHardwareDebugInfo())
291+
return error;
292+
293+
for (uint32_t i = 0; i < m_max_hbp_supported; i++)
294+
m_hbp_regs[i].control = 0;
295+
for (uint32_t i = 0; i < m_max_hwp_supported; i++)
296+
m_hwp_regs[i].control = 0;
297+
return WriteHardwareDebugRegs(eDREGTypeWATCH);
298+
#else
299+
return llvm::error::success();
300+
#endif
301+
}
302+
288303
#endif // defined (__aarch64__)

lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ class NativeRegisterContextFreeBSD_arm64
5858
llvm::Error
5959
CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override;
6060

61+
llvm::Error ClearDBRegs() override;
62+
6163
private:
6264
// Due to alignment, FreeBSD reg/fpreg are a few bytes larger than
6365
// LLDB's GPR/FPU structs. However, all fields have matching offsets

lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,4 +653,10 @@ NativeRegisterContextFreeBSD_x86_64::GetYMMSplitReg(uint32_t reg) {
653653
return YMMSplitPtr{&fpreg->sv_xmm[reg_index], &ymmreg[reg_index]};
654654
}
655655

656+
llvm::Error NativeRegisterContextFreeBSD_x86_64::ClearDBRegs() {
657+
uint64_t zero = 0;
658+
RegisterValue dr7{zero};
659+
return WriteRegister(GetDR(7), dr7).ToError();
660+
}
661+
656662
#endif // defined(__x86_64__)

lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ class NativeRegisterContextFreeBSD_x86_64
5555
llvm::Error
5656
CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override;
5757

58+
llvm::Error ClearDBRegs() override;
59+
5860
private:
5961
// Private member types.
6062
enum RegSetKind {

0 commit comments

Comments
 (0)