forked from lix-project/lix
gc: clean up error handling on Darwin
This commit is contained in:
parent
1cce5759c7
commit
474ea179fb
|
@ -330,6 +330,13 @@ Roots LocalStore::findRoots(bool censor)
|
||||||
|
|
||||||
typedef std::unordered_map<Path, std::unordered_set<std::string>> UncheckedRoots;
|
typedef std::unordered_map<Path, std::unordered_set<std::string>> UncheckedRoots;
|
||||||
|
|
||||||
|
static std::string quoteRegexChars(const std::string & raw)
|
||||||
|
{
|
||||||
|
static auto specialRegex = std::regex(R"([.^$\\*+?()\[\]{}|])");
|
||||||
|
return std::regex_replace(raw, specialRegex, R"(\$&)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __linux__
|
||||||
static void readProcLink(const std::string & file, UncheckedRoots & roots)
|
static void readProcLink(const std::string & file, UncheckedRoots & roots)
|
||||||
{
|
{
|
||||||
constexpr auto bufsiz = PATH_MAX;
|
constexpr auto bufsiz = PATH_MAX;
|
||||||
|
@ -348,13 +355,6 @@ static void readProcLink(const std::string & file, UncheckedRoots & roots)
|
||||||
.emplace(file);
|
.emplace(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string quoteRegexChars(const std::string & raw)
|
|
||||||
{
|
|
||||||
static auto specialRegex = std::regex(R"([.^$\\*+?()\[\]{}|])");
|
|
||||||
return std::regex_replace(raw, specialRegex, R"(\$&)");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if __linux__
|
|
||||||
static void readFileRoots(const char * path, UncheckedRoots & roots)
|
static void readFileRoots(const char * path, UncheckedRoots & roots)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
@ -445,43 +445,41 @@ static void readLibprocRoots(const Path & storeDir, UncheckedRoots & unchecked)
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
try {
|
||||||
// Process cwd/root directory
|
// Process cwd/root directory
|
||||||
struct proc_vnodepathinfo vnodeInfo;
|
struct proc_vnodepathinfo vnodeInfo;
|
||||||
if (proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vnodeInfo, sizeof(vnodeInfo)) <= 0) {
|
if (proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vnodeInfo, sizeof(vnodeInfo)) <= 0)
|
||||||
if ((errno == ESRCH) || (errno == EPERM)) continue;
|
|
||||||
throw SysError("Getting pid %1% working directory", pid);
|
throw SysError("Getting pid %1% working directory", pid);
|
||||||
};
|
|
||||||
unchecked[std::string(vnodeInfo.pvi_cdir.vip_path)].emplace("{libproc/cwd}");
|
unchecked[std::string(vnodeInfo.pvi_cdir.vip_path)].emplace("{libproc/cwd}");
|
||||||
unchecked[std::string(vnodeInfo.pvi_rdir.vip_path)].emplace("{libproc/rootdir}");
|
unchecked[std::string(vnodeInfo.pvi_rdir.vip_path)].emplace("{libproc/rootdir}");
|
||||||
|
|
||||||
|
|
||||||
// File descriptors
|
// File descriptors
|
||||||
int fdBufSize = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, nullptr, 0);
|
int fdBufSize = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, nullptr, 0);
|
||||||
if (fdBufSize <= 0) {
|
if (fdBufSize <= 0)
|
||||||
if ((errno == ESRCH) || (errno == EPERM)) continue;
|
|
||||||
throw SysError("Listing pid %1% file descriptors", pid);
|
throw SysError("Listing pid %1% file descriptors", pid);
|
||||||
}
|
|
||||||
std::vector<struct proc_fdinfo> fds(fdBufSize / sizeof(struct proc_fdinfo));
|
std::vector<struct proc_fdinfo> fds(fdBufSize / sizeof(struct proc_fdinfo));
|
||||||
fdBufSize = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds.data(), fds.size() * sizeof(struct proc_fdinfo));
|
fdBufSize = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds.data(), fds.size() * sizeof(struct proc_fdinfo));
|
||||||
if (fdBufSize <= 0) {
|
if (fdBufSize <= 0)
|
||||||
if ((errno == ESRCH) || (errno == EPERM)) continue;
|
|
||||||
throw SysError("Listing pid %1% file descriptors", pid);
|
throw SysError("Listing pid %1% file descriptors", pid);
|
||||||
}
|
|
||||||
fds.resize(fdBufSize / sizeof(struct proc_fdinfo));
|
fds.resize(fdBufSize / sizeof(struct proc_fdinfo));
|
||||||
|
|
||||||
for (auto fd: fds) {
|
for (auto fd: fds) {
|
||||||
// While there are names for other FD types, only vnodes are in the filesystem
|
// By definition, only a vnode is on the filesystem
|
||||||
if (fd.proc_fdtype != PROX_FDTYPE_VNODE)
|
if (fd.proc_fdtype != PROX_FDTYPE_VNODE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
struct vnode_fdinfowithpath fdInfo;
|
struct vnode_fdinfowithpath fdInfo;
|
||||||
if (proc_pidfdinfo(pid, fd.proc_fd, PROC_PIDFDVNODEPATHINFO, &fdInfo, sizeof(fdInfo)) <= 0) {
|
if (proc_pidfdinfo(pid, fd.proc_fd, PROC_PIDFDVNODEPATHINFO, &fdInfo, sizeof(fdInfo)) <= 0)
|
||||||
if ((errno == ESRCH) || (errno == EPERM) || (errno == EBADF)) continue;
|
|
||||||
throw SysError("Getting pid %1% fd %2% path", pid, fd.proc_fd);
|
throw SysError("Getting pid %1% fd %2% path", pid, fd.proc_fd);
|
||||||
}
|
|
||||||
unchecked[std::string(fdInfo.pvip.vip_path)].emplace("{libproc/fd}");
|
unchecked[std::string(fdInfo.pvip.vip_path)].emplace("{libproc/fd}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Regions (e.g. mmapped files, executables, shared libraries)
|
// Regions (e.g. mmapped files, executables, shared libraries)
|
||||||
struct proc_regionwithpathinfo regionInfo;
|
|
||||||
uint64_t nextAddr = 0;
|
uint64_t nextAddr = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
// Seriously, what are you doing XNU?
|
// Seriously, what are you doing XNU?
|
||||||
|
@ -490,21 +488,26 @@ static void readLibprocRoots(const Path & storeDir, UncheckedRoots & unchecked)
|
||||||
// * PROC_PIDREGIONPATHINFO2 includes regions backed by a vnode
|
// * PROC_PIDREGIONPATHINFO2 includes regions backed by a vnode
|
||||||
// * PROC_PIDREGIONPATHINFO3 includes regions backed by a vnode on a specified filesystem
|
// * PROC_PIDREGIONPATHINFO3 includes regions backed by a vnode on a specified filesystem
|
||||||
// Only PROC_PIDREGIONPATHINFO is documented.
|
// Only PROC_PIDREGIONPATHINFO is documented.
|
||||||
// Unfortunately, using it would make finding gcroots take about 50x as long
|
// Unfortunately, using it would make finding gcroots take about 100x as long
|
||||||
// and tests would fail from timeout.
|
// and tests would fail from timeout.
|
||||||
// According to the Frida source code, PROC_PIDREGIONPATHINFO2 has been available
|
// According to the Frida source code, PROC_PIDREGIONPATHINFO2 has been available
|
||||||
// since XNU 2782.1.97 in OS X 10.10
|
// since XNU 2782.1.97 in OS X 10.10
|
||||||
//
|
//
|
||||||
// This is PROC_PIDREGIONPATHINFO2
|
// 22 means PROC_PIDREGIONPATHINFO2
|
||||||
|
struct proc_regionwithpathinfo regionInfo;
|
||||||
if (proc_pidinfo(pid, 22, nextAddr, ®ionInfo, sizeof(regionInfo)) <= 0) {
|
if (proc_pidinfo(pid, 22, nextAddr, ®ionInfo, sizeof(regionInfo)) <= 0) {
|
||||||
if ((errno == ESRCH) || (errno == EINVAL) || (errno == EPERM)) break;
|
// PROC_PIDREGIONPATHINFO signals we're done with an error,
|
||||||
|
// so we're expected to hit this once per process
|
||||||
|
if (errno == ESRCH || errno == EINVAL) break;
|
||||||
throw SysError("Getting pid %1% region path", pid);
|
throw SysError("Getting pid %1% region path", pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
unchecked[std::string(regionInfo.prp_vip.vip_path)].emplace("{libproc/region}");
|
unchecked[std::string(regionInfo.prp_vip.vip_path)].emplace("{libproc/region}");
|
||||||
|
|
||||||
nextAddr = regionInfo.prp_prinfo.pri_address + regionInfo.prp_prinfo.pri_size;
|
nextAddr = regionInfo.prp_prinfo.pri_address + regionInfo.prp_prinfo.pri_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Arguments and environment variables
|
// Arguments and environment variables
|
||||||
// We can't read environment variables of binaries with with entitlements unless
|
// We can't read environment variables of binaries with with entitlements unless
|
||||||
// nix has the `com.apple.private.read-environment-variables` entitlement or SIP is off
|
// nix has the `com.apple.private.read-environment-variables` entitlement or SIP is off
|
||||||
|
@ -521,7 +524,6 @@ static void readLibprocRoots(const Path & storeDir, UncheckedRoots & unchecked)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> args(argsSize);
|
std::vector<char> args(argsSize);
|
||||||
|
|
||||||
if (sysctl(sysctlName, 3, args.data(), &argsSize, nullptr, 0) < 0) {
|
if (sysctl(sysctlName, 3, args.data(), &argsSize, nullptr, 0) < 0) {
|
||||||
throw SysError("Reading pid %1% arguments", pid);
|
throw SysError("Reading pid %1% arguments", pid);
|
||||||
}
|
}
|
||||||
|
@ -536,30 +538,30 @@ static void readLibprocRoots(const Path & storeDir, UncheckedRoots & unchecked)
|
||||||
|
|
||||||
// Per-thread working directories
|
// Per-thread working directories
|
||||||
struct proc_taskallinfo taskAllInfo;
|
struct proc_taskallinfo taskAllInfo;
|
||||||
if (proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, &taskAllInfo, sizeof(taskAllInfo)) <= 0) {
|
if (proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, &taskAllInfo, sizeof(taskAllInfo)) <= 0)
|
||||||
if ((errno == ESRCH) || (errno == EPERM)) continue;
|
|
||||||
throw SysError("Reading pid %1% tasks", pid);
|
throw SysError("Reading pid %1% tasks", pid);
|
||||||
}
|
|
||||||
|
|
||||||
// If the process doesn't have the per-thread cwd flag then we already have the
|
// If the process doesn't have the per-thread cwd flag then we already have the
|
||||||
// process-wide cwd from PROC_PIDVNODEPATHINFO
|
// process-wide cwd from PROC_PIDVNODEPATHINFO
|
||||||
if (taskAllInfo.pbsd.pbi_flags & PROC_FLAG_THCWD) {
|
if (taskAllInfo.pbsd.pbi_flags & PROC_FLAG_THCWD) {
|
||||||
std::vector<uint64_t> tids(taskAllInfo.ptinfo.pti_threadnum);
|
std::vector<uint64_t> tids(taskAllInfo.ptinfo.pti_threadnum);
|
||||||
int tidBufSize = proc_pidinfo(pid, PROC_PIDLISTTHREADS, 0, tids.data(), tids.size() * sizeof(uint64_t));
|
int tidBufSize = proc_pidinfo(pid, PROC_PIDLISTTHREADS, 0, tids.data(), tids.size() * sizeof(uint64_t));
|
||||||
if (tidBufSize <= 0) {
|
if (tidBufSize <= 0)
|
||||||
if ((errno == ESRCH) || (errno == EPERM)) continue;
|
|
||||||
throw SysError("Listing pid %1% threads", pid);
|
throw SysError("Listing pid %1% threads", pid);
|
||||||
}
|
|
||||||
|
|
||||||
for (auto tid: tids) {
|
for (auto tid: tids) {
|
||||||
struct proc_threadwithpathinfo threadPathInfo;
|
struct proc_threadwithpathinfo threadPathInfo;
|
||||||
if (proc_pidinfo(pid, PROC_PIDTHREADPATHINFO, tid, &threadPathInfo, sizeof(threadPathInfo)) <= 0) {
|
if (proc_pidinfo(pid, PROC_PIDTHREADPATHINFO, tid, &threadPathInfo, sizeof(threadPathInfo)) <= 0)
|
||||||
if ((errno == ESRCH) || (errno == EPERM)) continue;
|
|
||||||
throw SysError("Reading pid %1% thread %2% cwd", pid, tid);
|
throw SysError("Reading pid %1% thread %2% cwd", pid, tid);
|
||||||
}
|
|
||||||
unchecked[std::string(threadPathInfo.pvip.vip_path)].emplace("{libproc/threadcwd}");
|
unchecked[std::string(threadPathInfo.pvip.vip_path)].emplace("{libproc/threadcwd}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (SysError & e) {
|
||||||
|
if (errno == ENOENT || errno == EACCES || errno == ESRCH)
|
||||||
|
continue;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue