# include <mach/mach_time.h>
# include <mach/vm_statistics.h>
# include <malloc/malloc.h>
-# include <os/log.h>
+# if defined(__has_builtin) && __has_builtin(__builtin_os_log_format)
+# include <os/log.h>
+# else
+ /* Without support for __builtin_os_log_format, fall back to the older
+ method. */
+# define OS_LOG_DEFAULT 0
+# define os_log_error(A,B,C) \
+ asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", (C))
+# endif
# include <pthread.h>
# include <pthread/introspection.h>
# include <sched.h>
// When logging with os_log_error this will make it into the crash log.
if (internal_strncmp(SanitizerToolName, "AddressSanitizer",
sizeof("AddressSanitizer") - 1) == 0)
- SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Address Sanitizer reported a failure.");
+ SANITIZER_OS_LOG(OS_LOG_DEFAULT, "%{public}s",
+ "Address Sanitizer reported a failure.");
else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer",
sizeof("UndefinedBehaviorSanitizer") - 1) == 0)
- SANITIZER_OS_LOG(OS_LOG_DEFAULT,
+ SANITIZER_OS_LOG(OS_LOG_DEFAULT, "%{public}s",
"Undefined Behavior Sanitizer reported a failure.");
else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer",
sizeof("ThreadSanitizer") - 1) == 0)
- SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Thread Sanitizer reported a failure.");
+ SANITIZER_OS_LOG(OS_LOG_DEFAULT, "%{public}s",
+ "Thread Sanitizer reported a failure.");
else
- SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Sanitizer tool reported a failure.");
+ SANITIZER_OS_LOG(OS_LOG_DEFAULT, "%{public}s",
+ "Sanitizer tool reported a failure.");
if (common_flags()->log_to_syslog)
- SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Consult syslog for more information.");
+ SANITIZER_OS_LOG(OS_LOG_DEFAULT, "%{public}s",
+ "Consult syslog for more information.");
// Log to syslog.
// The logging on OS X may call pthread_create so we need the threading
GetPcSpBp(context, &pc, &sp, &bp);
}
+#ifndef KERN_DENIED
+#define KERN_DENIED 53
+#endif
+
// ASan/TSan use mmap in a way that creates “deallocation gaps” which triggers
// EXC_GUARD exceptions on macOS 10.15+ (XNU 19.0+).
static void DisableMmapExcGuardExceptions() {
extern bool _dyld_get_shared_cache_uuid(uuid_t uuid);
extern const void *_dyld_get_shared_cache_range(size_t *length);
extern intptr_t _dyld_get_image_slide(const struct mach_header* mh);
+} // extern "C"
+
+#ifdef __BLOCKS__
+extern "C" {
extern int dyld_shared_cache_iterate_text(
const uuid_t cacheUuid,
void (^callback)(const dyld_shared_cache_dylib_text_info *info));
} // extern "C"
-static mach_header *GetDyldImageHeaderViaSharedCache() {
- uuid_t uuid;
- bool hasCache = _dyld_get_shared_cache_uuid(uuid);
- if (!hasCache)
- return nullptr;
-
+static mach_header *GetDyldImageHeaderViaSharedCache(uuid_t uuid) {
size_t cacheLength;
- __block uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength);
+ const uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength);
CHECK(cacheStart && cacheLength);
__block mach_header *dyldHdr = nullptr;
return dyldHdr;
}
+#else
+
+/* Here we implement a manual emulation of the Blocks closure and callback
+ that is needed by dyld_shared_cache_iterate_text (). In the compiler-
+ generated code, the [local] names are mangled differently, but that
+ should not matter to the function (since all the entities are TU-local). */
+
+extern "C" {
+/* Some descriptions of the blocks interfaces/runtime that we need. */
+extern void *_NSConcreteStackBlock;
+extern void _Block_object_assign(void *, void *, int);
+extern void _Block_object_dispose(void *, int);
+enum {
+ BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)), block, ... */
+ BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */
+ BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the __block variable */
+ BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy helpers */
+ BLOCK_BYREF_CALLER = 128 /* called from __block (byref) copy/dispose support routines. */
+};
+
+/* 1. __block mach_header *dyldHdr; Uses this on-stack object. */
+typedef struct __block_byref_dyldHdr {
+ void *__isa;
+ struct __block_byref_dyldHdr *forwarding;
+ int flags; // 1<<25 iff we need copy helper;
+ int size;
+ mach_header *dyldHdr_cp;
+} dyldHdr_type;
+
+/* The closure, support functions and the actuall callback code. */
+/* 1. closure descriptor. A constant instance of this will be created. */
+struct Block_descriptor_cb {
+ unsigned long int reserved; // NULL
+ unsigned long int size; // sizeof(struct Block_literal_cb)
+ // optional helper functions
+ void (*copy_helper)(struct Block_literal_cb *dst, struct Block_literal_cb *src); // IFF (1<<25)
+ void (*dispose_helper)(struct Block_literal_cb *src); // IFF (1<<25)
+ // required ABI.2010.3.16
+ const char *signature; // IFF (1<<30)
+ void *no_idea; // not documented in the current ABI
+};
+
+/* 2. This is the closure object. In this case, it will be allocated on the
+ stack and does not need to be moved (since the closure never escapes
+ from its enclosing scope). However, the infrastructure still provides
+ support for moving it to the heap if required. */
+typedef struct Block_literal_cb {
+ void *__isa;
+ int flags;
+ int reserved;
+ void (*invoke) (Block_literal_cb*, const dyld_shared_cache_dylib_text_info *info);
+ const struct Block_descriptor_cb *descriptor;
+ dyldHdr_type *h_holder;
+ uptr cache_start;
+} CallbackBlk;
+
+/* 3. Supporting functions to allow for the closure to be copied to the heap on
+ demand. */
+static void
+__block_copy_cb (struct Block_literal_cb *dst, struct Block_literal_cb *src)
+{
+ //_Block_byref_assign_copy(&dst->captured_i, src->captured_i);
+ _Block_object_assign(&dst->h_holder, src->h_holder, BLOCK_FIELD_IS_BYREF);
+}
+
+static void
+__block_dispose_cb (struct Block_literal_cb *src) {
+ //_Block_byref_release(src->captured_i);
+ _Block_object_dispose(src->h_holder, BLOCK_FIELD_IS_BYREF);
+}
+
+/* 4. Here is the actual code implementing the callback. */
+static void
+__block_invoke_cb (struct Block_literal_cb *_block,
+ const dyld_shared_cache_dylib_text_info *info)
+{
+ mach_header *hdr = (mach_header *)(_block->cache_start + info->textSegmentOffset);
+ if (IsDyldHdr(hdr))
+ _block->h_holder->forwarding->dyldHdr_cp = hdr;
+}
+
+/* 6. The constant instance of the descriptor mentioned in 1 above. */
+static const struct Block_descriptor_cb cb_descr = {
+ 0, sizeof (struct Block_literal_cb), __block_copy_cb, __block_dispose_cb,
+ "v16@?0r^{dyld_shared_cache_dylib_text_info=QQQ[16C]*Q}8", nullptr
+};
+
+/* Declare dyld_shared_cache_iterate_text () as taking a regular pointer to
+ the closure; we cannot use the ^ syntax yet in GCC. */
+extern int dyld_shared_cache_iterate_text(const uuid_t cacheUuid, CallbackBlk*);
+} // extern "C"
+
+/* The non-blocks version of GetDyldImageHeaderViaSharedCache (). */
+static mach_header *GetDyldImageHeaderViaSharedCache(uuid_t uuid) {
+ size_t cacheLength;
+ const uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength);
+ CHECK(cacheStart && cacheLength);
+ /* __block mach_header *dyldHdr = nullptr; */
+ dyldHdr_type dyldHdr
+ = { nullptr, &dyldHdr, 0, sizeof (struct __block_byref_dyldHdr), nullptr };
+ /* Callback cb = ^(const dyld_shared_cache_dylib_text_info *info... */
+ CallbackBlk cb
+ = { _NSConcreteStackBlock, 0x42000000, 0, __block_invoke_cb,
+ &cb_descr, &dyldHdr, cacheStart };
+ int res = dyld_shared_cache_iterate_text ( uuid, &cb );
+ CHECK_EQ(res, 0);
+ return dyldHdr.forwarding->dyldHdr_cp;
+}
+#endif
+
const mach_header *get_dyld_hdr() {
if (!dyld_hdr) {
// On macOS 13+, dyld itself has moved into the shared cache. Looking it up
// via vm_region_recurse_64() causes spins/hangs/crashes.
if (GetMacosAlignedVersion() >= MacosVersion(13, 0)) {
- dyld_hdr = GetDyldImageHeaderViaSharedCache();
+ uuid_t uuid;
+ if (!_dyld_get_shared_cache_uuid(uuid))
+ VReport(1, "Failed get the shared cache on macOS 13+\n");
+ else
+ dyld_hdr = GetDyldImageHeaderViaSharedCache(uuid);
if (!dyld_hdr) {
VReport(1,
"Failed to lookup the dyld image header in the shared cache on "