mac: System libraries are no longer found on disk on macOS 11

On macOS 11, system libraries are no longer present on disk as
individual Mach-O files, but are shipped exclusively in the dyld shared
cache. This affects tests that verify the list of modules loaded into a
process. The new _dyld_shared_cache_contains_path function can be used
to determine whether a path exists in the dyld shared cache.

Bug: crashpad:347
Test: crashpad_snapshot_test ProcessReaderMac.{Self,Child}Modules
Change-Id: I19402e45701caeb850bdafd701ccbba4ef9c60bc
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2384322
Commit-Queue: Mark Mentovai <mark@chromium.org>
Reviewed-by: Robert Sesek <rsesek@chromium.org>
This commit is contained in:
Mark Mentovai 2020-08-31 13:46:40 -04:00 committed by Commit Bot
parent 56937e1df5
commit b3d84e0d05

View File

@ -16,17 +16,20 @@
#include <Availability.h>
#include <OpenCL/opencl.h>
#include <dlfcn.h>
#include <errno.h>
#include <mach-o/dyld.h>
#include <mach-o/dyld_images.h>
#include <mach/mach.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <map>
#include <utility>
#include "base/check_op.h"
#include "base/logging.h"
#include "base/mac/mach_logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/stl_util.h"
@ -530,6 +533,75 @@ TEST(ProcessReaderMac, ChildSeveralThreads) {
process_reader_threaded_child.Run();
}
template <typename T>
T GetDyldFunction(const char* symbol) {
static void* dl_handle = []() -> void* {
Dl_info dl_info;
if (!dladdr(reinterpret_cast<void*>(dlopen), &dl_info)) {
LOG(ERROR) << "dladdr: failed";
return nullptr;
}
void* dl_handle =
dlopen(dl_info.dli_fname, RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
DCHECK(dl_handle) << "dlopen: " << dlerror();
return dl_handle;
}();
if (!dl_handle) {
return nullptr;
}
return reinterpret_cast<T>(dlsym(dl_handle, symbol));
}
void VerifyImageExistenceAndTimestamp(const char* path, time_t timestamp) {
const char* stat_path;
bool timestamp_may_be_0;
#if __MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_16
static auto _dyld_shared_cache_contains_path =
GetDyldFunction<bool (*)(const char*)>(
"_dyld_shared_cache_contains_path");
#endif
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability"
if (_dyld_shared_cache_contains_path &&
_dyld_shared_cache_contains_path(path)) {
#pragma clang diagnostic pop
// The timestamp will either match the timestamp of the dyld_shared_cache
// file in use, or be 0.
static const char* dyld_shared_cache_file_path = []() -> const char* {
auto dyld_shared_cache_file_path_f =
GetDyldFunction<const char* (*)()>("dyld_shared_cache_file_path");
// dyld_shared_cache_file_path should always be present if
// _dyld_shared_cache_contains_path is.
DCHECK(dyld_shared_cache_file_path_f);
const char* dyld_shared_cache_file_path = dyld_shared_cache_file_path_f();
DCHECK(dyld_shared_cache_file_path);
return dyld_shared_cache_file_path;
}();
stat_path = dyld_shared_cache_file_path;
timestamp_may_be_0 = true;
} else {
stat_path = path;
timestamp_may_be_0 = false;
}
struct stat stat_buf;
int rv = stat(stat_path, &stat_buf);
EXPECT_EQ(rv, 0) << ErrnoMessage("stat");
if (rv == 0 && (!timestamp_may_be_0 || timestamp != 0)) {
EXPECT_EQ(timestamp, stat_buf.st_mtime);
}
}
// cl_kernels images (OpenCL kernels) are weird. Theyre not ld output and dont
// exist as files on disk. On OS X 10.10 and 10.11, their Mach-O structure isnt
// perfect. They show up loaded into many executables, so these quirks should be
@ -695,12 +767,8 @@ TEST(ProcessReaderMac, SelfModules) {
found_cl_kernels = true;
} else {
// Hope that the module didnt change on disk.
struct stat stat_buf;
int rv = stat(dyld_image_name, &stat_buf);
EXPECT_EQ(rv, 0) << ErrnoMessage("stat");
if (rv == 0) {
EXPECT_EQ(modules[index].timestamp, stat_buf.st_mtime);
}
VerifyImageExistenceAndTimestamp(dyld_image_name,
modules[index].timestamp);
}
}
@ -785,12 +853,8 @@ class ProcessReaderModulesChild final : public MachMultiprocess {
found_cl_kernels = true;
} else {
// Hope that the module didnt change on disk.
struct stat stat_buf;
int rv = stat(expect_name.c_str(), &stat_buf);
EXPECT_EQ(rv, 0) << ErrnoMessage("stat");
if (rv == 0) {
EXPECT_EQ(modules[index].timestamp, stat_buf.st_mtime);
}
VerifyImageExistenceAndTimestamp(expect_name.c_str(),
modules[index].timestamp);
}
}