Changeset View
Changeset View
Standalone View
Standalone View
compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp
//===-- sanitizer_procmaps_mac.cpp ----------------------------------------===// | //===-- sanitizer_procmaps_mac.cpp ----------------------------------------===// | ||||
Lint: Lint: clang-format not found in user’s local PATH; not linting file. | |||||
// | // | ||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
// See https://llvm.org/LICENSE.txt for license information. | // See https://llvm.org/LICENSE.txt for license information. | ||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
// | // | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
// | // | ||||
▲ Show 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | |||||
void MemoryMappingLayout::CacheMemoryMappings() { | void MemoryMappingLayout::CacheMemoryMappings() { | ||||
// No-op on Mac for now. | // No-op on Mac for now. | ||||
} | } | ||||
void MemoryMappingLayout::LoadFromCache() { | void MemoryMappingLayout::LoadFromCache() { | ||||
// No-op on Mac for now. | // No-op on Mac for now. | ||||
} | } | ||||
static bool IsDyldHdr(const mach_header *hdr) { | |||||
return (hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) && | |||||
hdr->filetype == MH_DYLINKER; | |||||
} | |||||
// _dyld_get_image_header() and related APIs don't report dyld itself. | // _dyld_get_image_header() and related APIs don't report dyld itself. | ||||
// We work around this by manually recursing through the memory map | // We work around this by manually recursing through the memory map | ||||
// until we hit a Mach header matching dyld instead. These recurse | // until we hit a Mach header matching dyld instead. These recurse | ||||
// calls are expensive, but the first memory map generation occurs | // calls are expensive, but the first memory map generation occurs | ||||
// early in the process, when dyld is one of the only images loaded, | // early in the process, when dyld is one of the only images loaded, | ||||
// so it will be hit after only a few iterations. | // so it will be hit after only a few iterations. These assumptions don't hold | ||||
static mach_header *get_dyld_image_header() { | // on macOS 13+ anymore (dyld itself has moved into the shared cache). | ||||
static mach_header *GetDyldImageHeaderViaVMRegion() { | |||||
vm_address_t address = 0; | vm_address_t address = 0; | ||||
while (true) { | while (true) { | ||||
vm_size_t size = 0; | vm_size_t size = 0; | ||||
unsigned depth = 1; | unsigned depth = 1; | ||||
struct vm_region_submap_info_64 info; | struct vm_region_submap_info_64 info; | ||||
mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; | mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; | ||||
kern_return_t err = | kern_return_t err = | ||||
vm_region_recurse_64(mach_task_self(), &address, &size, &depth, | vm_region_recurse_64(mach_task_self(), &address, &size, &depth, | ||||
(vm_region_info_t)&info, &count); | (vm_region_info_t)&info, &count); | ||||
if (err != KERN_SUCCESS) return nullptr; | if (err != KERN_SUCCESS) return nullptr; | ||||
if (size >= sizeof(mach_header) && info.protection & kProtectionRead) { | if (size >= sizeof(mach_header) && info.protection & kProtectionRead) { | ||||
mach_header *hdr = (mach_header *)address; | mach_header *hdr = (mach_header *)address; | ||||
if ((hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) && | if (IsDyldHdr(hdr)) { | ||||
hdr->filetype == MH_DYLINKER) { | |||||
return hdr; | return hdr; | ||||
} | } | ||||
} | } | ||||
address += size; | address += size; | ||||
} | } | ||||
} | } | ||||
extern "C" { | |||||
struct dyld_shared_cache_dylib_text_info { | |||||
uint64_t version; // current version 2 | |||||
// following fields all exist in version 1 | |||||
uint64_t loadAddressUnslid; | |||||
uint64_t textSegmentSize; | |||||
uuid_t dylibUuid; | |||||
const char *path; // pointer invalid at end of iterations | |||||
// following fields all exist in version 2 | |||||
uint64_t textSegmentOffset; // offset from start of cache | |||||
}; | |||||
typedef struct dyld_shared_cache_dylib_text_info | |||||
dyld_shared_cache_dylib_text_info; | |||||
extern bool _dyld_get_shared_cache_uuid(uuid_t uuid); | |||||
extern const void *_dyld_get_shared_cache_range(size_t *length); | |||||
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; | |||||
size_t cacheLength; | |||||
__block uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength); | |||||
CHECK(cacheStart && cacheLength); | |||||
__block mach_header *dyld_hdr = nullptr; | |||||
int res = dyld_shared_cache_iterate_text( | |||||
uuid, ^(const dyld_shared_cache_dylib_text_info *info) { | |||||
mach_header *hdr = | |||||
(mach_header *)(cacheStart + info->textSegmentOffset); | |||||
if (IsDyldHdr(hdr)) | |||||
dyld_hdr = hdr; | |||||
}); | |||||
CHECK_EQ(res, 0); | |||||
return dyld_hdr; | |||||
} | |||||
const mach_header *get_dyld_hdr() { | const mach_header *get_dyld_hdr() { | ||||
if (!dyld_hdr) dyld_hdr = get_dyld_image_header(); | 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. | |||||
bool dyldInSharedCache = GetMacosAlignedVersion() >= MacosVersion(13, 0); | |||||
if (dyldInSharedCache) { | |||||
dyld_hdr = GetDyldImageHeaderViaSharedCache(); | |||||
} | |||||
if (!dyld_hdr) { | |||||
if (dyldInSharedCache) { | |||||
Printf( | |||||
"Failed to lookup the dyld image header in the shared cache on " | |||||
"macOS 13+ (or no shared cache in use). Falling back to " | |||||
"vm_region_recurse_64() to lookup the dyld image header.\n"); | |||||
} | |||||
dyld_hdr = GetDyldImageHeaderViaVMRegion(); | |||||
} | |||||
CHECK(dyld_hdr); | |||||
} | |||||
return dyld_hdr; | return dyld_hdr; | ||||
} | } | ||||
// Next and NextSegmentLoad were inspired by base/sysinfo.cc in | // Next and NextSegmentLoad were inspired by base/sysinfo.cc in | ||||
// Google Perftools, https://github.com/gperftools/gperftools. | // Google Perftools, https://github.com/gperftools/gperftools. | ||||
// NextSegmentLoad scans the current image for the next segment load command | // NextSegmentLoad scans the current image for the next segment load command | ||||
▲ Show 20 Lines • Show All 201 Lines • Show Last 20 Lines |
clang-format not found in user’s local PATH; not linting file.