168d75effSDimitry Andric //===-- sanitizer_procmaps_mac.cpp ----------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // Information about the process mappings (Mac-specific parts).
1068d75effSDimitry Andric //===----------------------------------------------------------------------===//
1168d75effSDimitry Andric
1268d75effSDimitry Andric #include "sanitizer_platform.h"
1381ad6265SDimitry Andric #if SANITIZER_APPLE
1468d75effSDimitry Andric #include "sanitizer_common.h"
1568d75effSDimitry Andric #include "sanitizer_placement_new.h"
1668d75effSDimitry Andric #include "sanitizer_procmaps.h"
1768d75effSDimitry Andric
1868d75effSDimitry Andric #include <mach-o/dyld.h>
1968d75effSDimitry Andric #include <mach-o/loader.h>
2068d75effSDimitry Andric #include <mach/mach.h>
2168d75effSDimitry Andric
2268d75effSDimitry Andric // These are not available in older macOS SDKs.
2368d75effSDimitry Andric #ifndef CPU_SUBTYPE_X86_64_H
2468d75effSDimitry Andric #define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) /* Haswell */
2568d75effSDimitry Andric #endif
2668d75effSDimitry Andric #ifndef CPU_SUBTYPE_ARM_V7S
2768d75effSDimitry Andric #define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t)11) /* Swift */
2868d75effSDimitry Andric #endif
2968d75effSDimitry Andric #ifndef CPU_SUBTYPE_ARM_V7K
3068d75effSDimitry Andric #define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t)12)
3168d75effSDimitry Andric #endif
3268d75effSDimitry Andric #ifndef CPU_TYPE_ARM64
3368d75effSDimitry Andric #define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
3468d75effSDimitry Andric #endif
3568d75effSDimitry Andric
3668d75effSDimitry Andric namespace __sanitizer {
3768d75effSDimitry Andric
3868d75effSDimitry Andric // Contains information used to iterate through sections.
3968d75effSDimitry Andric struct MemoryMappedSegmentData {
4068d75effSDimitry Andric char name[kMaxSegName];
4168d75effSDimitry Andric uptr nsects;
4268d75effSDimitry Andric const char *current_load_cmd_addr;
4368d75effSDimitry Andric u32 lc_type;
4468d75effSDimitry Andric uptr base_virt_addr;
4568d75effSDimitry Andric uptr addr_mask;
4668d75effSDimitry Andric };
4768d75effSDimitry Andric
4868d75effSDimitry Andric template <typename Section>
NextSectionLoad(LoadedModule * module,MemoryMappedSegmentData * data,bool isWritable)4968d75effSDimitry Andric static void NextSectionLoad(LoadedModule *module, MemoryMappedSegmentData *data,
5068d75effSDimitry Andric bool isWritable) {
5168d75effSDimitry Andric const Section *sc = (const Section *)data->current_load_cmd_addr;
5268d75effSDimitry Andric data->current_load_cmd_addr += sizeof(Section);
5368d75effSDimitry Andric
5468d75effSDimitry Andric uptr sec_start = (sc->addr & data->addr_mask) + data->base_virt_addr;
5568d75effSDimitry Andric uptr sec_end = sec_start + sc->size;
5668d75effSDimitry Andric module->addAddressRange(sec_start, sec_end, /*executable=*/false, isWritable,
5768d75effSDimitry Andric sc->sectname);
5868d75effSDimitry Andric }
5968d75effSDimitry Andric
AddAddressRanges(LoadedModule * module)6068d75effSDimitry Andric void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) {
6168d75effSDimitry Andric // Don't iterate over sections when the caller hasn't set up the
6268d75effSDimitry Andric // data pointer, when there are no sections, or when the segment
6368d75effSDimitry Andric // is executable. Avoid iterating over executable sections because
6468d75effSDimitry Andric // it will confuse libignore, and because the extra granularity
6568d75effSDimitry Andric // of information is not needed by any sanitizers.
6668d75effSDimitry Andric if (!data_ || !data_->nsects || IsExecutable()) {
6768d75effSDimitry Andric module->addAddressRange(start, end, IsExecutable(), IsWritable(),
6868d75effSDimitry Andric data_ ? data_->name : nullptr);
6968d75effSDimitry Andric return;
7068d75effSDimitry Andric }
7168d75effSDimitry Andric
7268d75effSDimitry Andric do {
7368d75effSDimitry Andric if (data_->lc_type == LC_SEGMENT) {
7468d75effSDimitry Andric NextSectionLoad<struct section>(module, data_, IsWritable());
7568d75effSDimitry Andric #ifdef MH_MAGIC_64
7668d75effSDimitry Andric } else if (data_->lc_type == LC_SEGMENT_64) {
7768d75effSDimitry Andric NextSectionLoad<struct section_64>(module, data_, IsWritable());
7868d75effSDimitry Andric #endif
7968d75effSDimitry Andric }
8068d75effSDimitry Andric } while (--data_->nsects);
8168d75effSDimitry Andric }
8268d75effSDimitry Andric
MemoryMappingLayout(bool cache_enabled)8368d75effSDimitry Andric MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
8468d75effSDimitry Andric Reset();
8568d75effSDimitry Andric }
8668d75effSDimitry Andric
~MemoryMappingLayout()8768d75effSDimitry Andric MemoryMappingLayout::~MemoryMappingLayout() {
8868d75effSDimitry Andric }
8968d75effSDimitry Andric
Error() const9068d75effSDimitry Andric bool MemoryMappingLayout::Error() const {
9168d75effSDimitry Andric return false;
9268d75effSDimitry Andric }
9368d75effSDimitry Andric
9468d75effSDimitry Andric // More information about Mach-O headers can be found in mach-o/loader.h
9568d75effSDimitry Andric // Each Mach-O image has a header (mach_header or mach_header_64) starting with
9668d75effSDimitry Andric // a magic number, and a list of linker load commands directly following the
9768d75effSDimitry Andric // header.
9868d75effSDimitry Andric // A load command is at least two 32-bit words: the command type and the
9968d75effSDimitry Andric // command size in bytes. We're interested only in segment load commands
10068d75effSDimitry Andric // (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
10168d75effSDimitry Andric // into the task's address space.
10268d75effSDimitry Andric // The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
10368d75effSDimitry Andric // segment_command_64 correspond to the memory address, memory size and the
10468d75effSDimitry Andric // file offset of the current memory segment.
10568d75effSDimitry Andric // Because these fields are taken from the images as is, one needs to add
10668d75effSDimitry Andric // _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.
10768d75effSDimitry Andric
Reset()10868d75effSDimitry Andric void MemoryMappingLayout::Reset() {
10968d75effSDimitry Andric // Count down from the top.
11068d75effSDimitry Andric // TODO(glider): as per man 3 dyld, iterating over the headers with
11168d75effSDimitry Andric // _dyld_image_count is thread-unsafe. We need to register callbacks for
11268d75effSDimitry Andric // adding and removing images which will invalidate the MemoryMappingLayout
11368d75effSDimitry Andric // state.
11468d75effSDimitry Andric data_.current_image = _dyld_image_count();
11568d75effSDimitry Andric data_.current_load_cmd_count = -1;
11668d75effSDimitry Andric data_.current_load_cmd_addr = 0;
11768d75effSDimitry Andric data_.current_magic = 0;
11868d75effSDimitry Andric data_.current_filetype = 0;
11968d75effSDimitry Andric data_.current_arch = kModuleArchUnknown;
12068d75effSDimitry Andric internal_memset(data_.current_uuid, 0, kModuleUUIDSize);
12168d75effSDimitry Andric }
12268d75effSDimitry Andric
12368d75effSDimitry Andric // The dyld load address should be unchanged throughout process execution,
12468d75effSDimitry Andric // and it is expensive to compute once many libraries have been loaded,
12568d75effSDimitry Andric // so cache it here and do not reset.
12668d75effSDimitry Andric static mach_header *dyld_hdr = 0;
12768d75effSDimitry Andric static const char kDyldPath[] = "/usr/lib/dyld";
12868d75effSDimitry Andric static const int kDyldImageIdx = -1;
12968d75effSDimitry Andric
13068d75effSDimitry Andric // static
CacheMemoryMappings()13168d75effSDimitry Andric void MemoryMappingLayout::CacheMemoryMappings() {
13268d75effSDimitry Andric // No-op on Mac for now.
13368d75effSDimitry Andric }
13468d75effSDimitry Andric
LoadFromCache()13568d75effSDimitry Andric void MemoryMappingLayout::LoadFromCache() {
13668d75effSDimitry Andric // No-op on Mac for now.
13768d75effSDimitry Andric }
13868d75effSDimitry Andric
IsDyldHdr(const mach_header * hdr)13981ad6265SDimitry Andric static bool IsDyldHdr(const mach_header *hdr) {
14081ad6265SDimitry Andric return (hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) &&
14181ad6265SDimitry Andric hdr->filetype == MH_DYLINKER;
14281ad6265SDimitry Andric }
14381ad6265SDimitry Andric
14468d75effSDimitry Andric // _dyld_get_image_header() and related APIs don't report dyld itself.
14568d75effSDimitry Andric // We work around this by manually recursing through the memory map
14668d75effSDimitry Andric // until we hit a Mach header matching dyld instead. These recurse
14768d75effSDimitry Andric // calls are expensive, but the first memory map generation occurs
14868d75effSDimitry Andric // early in the process, when dyld is one of the only images loaded,
14981ad6265SDimitry Andric // so it will be hit after only a few iterations. These assumptions don't hold
15081ad6265SDimitry Andric // on macOS 13+ anymore (dyld itself has moved into the shared cache).
GetDyldImageHeaderViaVMRegion()15181ad6265SDimitry Andric static mach_header *GetDyldImageHeaderViaVMRegion() {
15268d75effSDimitry Andric vm_address_t address = 0;
15368d75effSDimitry Andric
15468d75effSDimitry Andric while (true) {
15504eeddc0SDimitry Andric vm_size_t size = 0;
15604eeddc0SDimitry Andric unsigned depth = 1;
15768d75effSDimitry Andric struct vm_region_submap_info_64 info;
15804eeddc0SDimitry Andric mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
15904eeddc0SDimitry Andric kern_return_t err =
16004eeddc0SDimitry Andric vm_region_recurse_64(mach_task_self(), &address, &size, &depth,
16168d75effSDimitry Andric (vm_region_info_t)&info, &count);
16268d75effSDimitry Andric if (err != KERN_SUCCESS) return nullptr;
16368d75effSDimitry Andric
16468d75effSDimitry Andric if (size >= sizeof(mach_header) && info.protection & kProtectionRead) {
16568d75effSDimitry Andric mach_header *hdr = (mach_header *)address;
16681ad6265SDimitry Andric if (IsDyldHdr(hdr)) {
16768d75effSDimitry Andric return hdr;
16868d75effSDimitry Andric }
16968d75effSDimitry Andric }
17068d75effSDimitry Andric address += size;
17168d75effSDimitry Andric }
17268d75effSDimitry Andric }
17368d75effSDimitry Andric
17481ad6265SDimitry Andric extern "C" {
17581ad6265SDimitry Andric struct dyld_shared_cache_dylib_text_info {
17681ad6265SDimitry Andric uint64_t version; // current version 2
17781ad6265SDimitry Andric // following fields all exist in version 1
17881ad6265SDimitry Andric uint64_t loadAddressUnslid;
17981ad6265SDimitry Andric uint64_t textSegmentSize;
18081ad6265SDimitry Andric uuid_t dylibUuid;
18181ad6265SDimitry Andric const char *path; // pointer invalid at end of iterations
18281ad6265SDimitry Andric // following fields all exist in version 2
18381ad6265SDimitry Andric uint64_t textSegmentOffset; // offset from start of cache
18481ad6265SDimitry Andric };
18581ad6265SDimitry Andric typedef struct dyld_shared_cache_dylib_text_info
18681ad6265SDimitry Andric dyld_shared_cache_dylib_text_info;
18781ad6265SDimitry Andric
18881ad6265SDimitry Andric extern bool _dyld_get_shared_cache_uuid(uuid_t uuid);
18981ad6265SDimitry Andric extern const void *_dyld_get_shared_cache_range(size_t *length);
19081ad6265SDimitry Andric extern int dyld_shared_cache_iterate_text(
19181ad6265SDimitry Andric const uuid_t cacheUuid,
19281ad6265SDimitry Andric void (^callback)(const dyld_shared_cache_dylib_text_info *info));
19381ad6265SDimitry Andric } // extern "C"
19481ad6265SDimitry Andric
GetDyldImageHeaderViaSharedCache()19581ad6265SDimitry Andric static mach_header *GetDyldImageHeaderViaSharedCache() {
19681ad6265SDimitry Andric uuid_t uuid;
19781ad6265SDimitry Andric bool hasCache = _dyld_get_shared_cache_uuid(uuid);
19881ad6265SDimitry Andric if (!hasCache)
19981ad6265SDimitry Andric return nullptr;
20081ad6265SDimitry Andric
20181ad6265SDimitry Andric size_t cacheLength;
20281ad6265SDimitry Andric __block uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength);
20381ad6265SDimitry Andric CHECK(cacheStart && cacheLength);
20481ad6265SDimitry Andric
20581ad6265SDimitry Andric __block mach_header *dyldHdr = nullptr;
20681ad6265SDimitry Andric int res = dyld_shared_cache_iterate_text(
20781ad6265SDimitry Andric uuid, ^(const dyld_shared_cache_dylib_text_info *info) {
20881ad6265SDimitry Andric CHECK_GE(info->version, 2);
20981ad6265SDimitry Andric mach_header *hdr =
21081ad6265SDimitry Andric (mach_header *)(cacheStart + info->textSegmentOffset);
21181ad6265SDimitry Andric if (IsDyldHdr(hdr))
21281ad6265SDimitry Andric dyldHdr = hdr;
21381ad6265SDimitry Andric });
21481ad6265SDimitry Andric CHECK_EQ(res, 0);
21581ad6265SDimitry Andric
21681ad6265SDimitry Andric return dyldHdr;
21781ad6265SDimitry Andric }
21881ad6265SDimitry Andric
get_dyld_hdr()21968d75effSDimitry Andric const mach_header *get_dyld_hdr() {
22081ad6265SDimitry Andric if (!dyld_hdr) {
22181ad6265SDimitry Andric // On macOS 13+, dyld itself has moved into the shared cache. Looking it up
22281ad6265SDimitry Andric // via vm_region_recurse_64() causes spins/hangs/crashes.
22381ad6265SDimitry Andric if (GetMacosAlignedVersion() >= MacosVersion(13, 0)) {
22481ad6265SDimitry Andric dyld_hdr = GetDyldImageHeaderViaSharedCache();
22581ad6265SDimitry Andric if (!dyld_hdr) {
226753f127fSDimitry Andric VReport(1,
22781ad6265SDimitry Andric "Failed to lookup the dyld image header in the shared cache on "
228753f127fSDimitry Andric "macOS 13+ (or no shared cache in use). Falling back to "
229753f127fSDimitry Andric "lookup via vm_region_recurse_64().\n");
23081ad6265SDimitry Andric dyld_hdr = GetDyldImageHeaderViaVMRegion();
23181ad6265SDimitry Andric }
23281ad6265SDimitry Andric } else {
23381ad6265SDimitry Andric dyld_hdr = GetDyldImageHeaderViaVMRegion();
23481ad6265SDimitry Andric }
23581ad6265SDimitry Andric CHECK(dyld_hdr);
23681ad6265SDimitry Andric }
23768d75effSDimitry Andric
23868d75effSDimitry Andric return dyld_hdr;
23968d75effSDimitry Andric }
24068d75effSDimitry Andric
24168d75effSDimitry Andric // Next and NextSegmentLoad were inspired by base/sysinfo.cc in
24268d75effSDimitry Andric // Google Perftools, https://github.com/gperftools/gperftools.
24368d75effSDimitry Andric
24468d75effSDimitry Andric // NextSegmentLoad scans the current image for the next segment load command
24568d75effSDimitry Andric // and returns the start and end addresses and file offset of the corresponding
24668d75effSDimitry Andric // segment.
24768d75effSDimitry Andric // Note that the segment addresses are not necessarily sorted.
24868d75effSDimitry Andric template <u32 kLCSegment, typename SegmentCommand>
NextSegmentLoad(MemoryMappedSegment * segment,MemoryMappedSegmentData * seg_data,MemoryMappingLayoutData * layout_data)24968d75effSDimitry Andric static bool NextSegmentLoad(MemoryMappedSegment *segment,
25068d75effSDimitry Andric MemoryMappedSegmentData *seg_data,
25168d75effSDimitry Andric MemoryMappingLayoutData *layout_data) {
25268d75effSDimitry Andric const char *lc = layout_data->current_load_cmd_addr;
253*06c3fb27SDimitry Andric
25468d75effSDimitry Andric layout_data->current_load_cmd_addr += ((const load_command *)lc)->cmdsize;
255*06c3fb27SDimitry Andric layout_data->current_load_cmd_count--;
25668d75effSDimitry Andric if (((const load_command *)lc)->cmd == kLCSegment) {
25768d75effSDimitry Andric const SegmentCommand* sc = (const SegmentCommand *)lc;
25868d75effSDimitry Andric uptr base_virt_addr, addr_mask;
25968d75effSDimitry Andric if (layout_data->current_image == kDyldImageIdx) {
26068d75effSDimitry Andric base_virt_addr = (uptr)get_dyld_hdr();
26168d75effSDimitry Andric // vmaddr is masked with 0xfffff because on macOS versions < 10.12,
26268d75effSDimitry Andric // it contains an absolute address rather than an offset for dyld.
26368d75effSDimitry Andric // To make matters even more complicated, this absolute address
26468d75effSDimitry Andric // isn't actually the absolute segment address, but the offset portion
26568d75effSDimitry Andric // of the address is accurate when combined with the dyld base address,
26668d75effSDimitry Andric // and the mask will give just this offset.
26768d75effSDimitry Andric addr_mask = 0xfffff;
26868d75effSDimitry Andric } else {
26968d75effSDimitry Andric base_virt_addr =
27068d75effSDimitry Andric (uptr)_dyld_get_image_vmaddr_slide(layout_data->current_image);
27168d75effSDimitry Andric addr_mask = ~0;
27268d75effSDimitry Andric }
27368d75effSDimitry Andric
27468d75effSDimitry Andric segment->start = (sc->vmaddr & addr_mask) + base_virt_addr;
27568d75effSDimitry Andric segment->end = segment->start + sc->vmsize;
27668d75effSDimitry Andric // Most callers don't need section information, so only fill this struct
27768d75effSDimitry Andric // when required.
27868d75effSDimitry Andric if (seg_data) {
27968d75effSDimitry Andric seg_data->nsects = sc->nsects;
28068d75effSDimitry Andric seg_data->current_load_cmd_addr =
28168d75effSDimitry Andric (const char *)lc + sizeof(SegmentCommand);
28268d75effSDimitry Andric seg_data->lc_type = kLCSegment;
28368d75effSDimitry Andric seg_data->base_virt_addr = base_virt_addr;
28468d75effSDimitry Andric seg_data->addr_mask = addr_mask;
28568d75effSDimitry Andric internal_strncpy(seg_data->name, sc->segname,
28668d75effSDimitry Andric ARRAY_SIZE(seg_data->name));
28768d75effSDimitry Andric }
28868d75effSDimitry Andric
28968d75effSDimitry Andric // Return the initial protection.
29068d75effSDimitry Andric segment->protection = sc->initprot;
29168d75effSDimitry Andric segment->offset = (layout_data->current_filetype ==
29268d75effSDimitry Andric /*MH_EXECUTE*/ 0x2)
29368d75effSDimitry Andric ? sc->vmaddr
29468d75effSDimitry Andric : sc->fileoff;
29568d75effSDimitry Andric if (segment->filename) {
29668d75effSDimitry Andric const char *src = (layout_data->current_image == kDyldImageIdx)
29768d75effSDimitry Andric ? kDyldPath
29868d75effSDimitry Andric : _dyld_get_image_name(layout_data->current_image);
29968d75effSDimitry Andric internal_strncpy(segment->filename, src, segment->filename_size);
30068d75effSDimitry Andric }
30168d75effSDimitry Andric segment->arch = layout_data->current_arch;
30268d75effSDimitry Andric internal_memcpy(segment->uuid, layout_data->current_uuid, kModuleUUIDSize);
30368d75effSDimitry Andric return true;
30468d75effSDimitry Andric }
30568d75effSDimitry Andric return false;
30668d75effSDimitry Andric }
30768d75effSDimitry Andric
ModuleArchFromCpuType(cpu_type_t cputype,cpu_subtype_t cpusubtype)30868d75effSDimitry Andric ModuleArch ModuleArchFromCpuType(cpu_type_t cputype, cpu_subtype_t cpusubtype) {
30968d75effSDimitry Andric cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK;
31068d75effSDimitry Andric switch (cputype) {
31168d75effSDimitry Andric case CPU_TYPE_I386:
31268d75effSDimitry Andric return kModuleArchI386;
31368d75effSDimitry Andric case CPU_TYPE_X86_64:
31468d75effSDimitry Andric if (cpusubtype == CPU_SUBTYPE_X86_64_ALL) return kModuleArchX86_64;
31568d75effSDimitry Andric if (cpusubtype == CPU_SUBTYPE_X86_64_H) return kModuleArchX86_64H;
31668d75effSDimitry Andric CHECK(0 && "Invalid subtype of x86_64");
31768d75effSDimitry Andric return kModuleArchUnknown;
31868d75effSDimitry Andric case CPU_TYPE_ARM:
31968d75effSDimitry Andric if (cpusubtype == CPU_SUBTYPE_ARM_V6) return kModuleArchARMV6;
32068d75effSDimitry Andric if (cpusubtype == CPU_SUBTYPE_ARM_V7) return kModuleArchARMV7;
32168d75effSDimitry Andric if (cpusubtype == CPU_SUBTYPE_ARM_V7S) return kModuleArchARMV7S;
32268d75effSDimitry Andric if (cpusubtype == CPU_SUBTYPE_ARM_V7K) return kModuleArchARMV7K;
32368d75effSDimitry Andric CHECK(0 && "Invalid subtype of ARM");
32468d75effSDimitry Andric return kModuleArchUnknown;
32568d75effSDimitry Andric case CPU_TYPE_ARM64:
32668d75effSDimitry Andric return kModuleArchARM64;
32768d75effSDimitry Andric default:
32868d75effSDimitry Andric CHECK(0 && "Invalid CPU type");
32968d75effSDimitry Andric return kModuleArchUnknown;
33068d75effSDimitry Andric }
33168d75effSDimitry Andric }
33268d75effSDimitry Andric
NextCommand(const load_command * lc)33368d75effSDimitry Andric static const load_command *NextCommand(const load_command *lc) {
33468d75effSDimitry Andric return (const load_command *)((const char *)lc + lc->cmdsize);
33568d75effSDimitry Andric }
33668d75effSDimitry Andric
FindUUID(const load_command * first_lc,u8 * uuid_output)33768d75effSDimitry Andric static void FindUUID(const load_command *first_lc, u8 *uuid_output) {
33868d75effSDimitry Andric for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) {
33968d75effSDimitry Andric if (lc->cmd != LC_UUID) continue;
34068d75effSDimitry Andric
34168d75effSDimitry Andric const uuid_command *uuid_lc = (const uuid_command *)lc;
34268d75effSDimitry Andric const uint8_t *uuid = &uuid_lc->uuid[0];
34368d75effSDimitry Andric internal_memcpy(uuid_output, uuid, kModuleUUIDSize);
34468d75effSDimitry Andric return;
34568d75effSDimitry Andric }
34668d75effSDimitry Andric }
34768d75effSDimitry Andric
IsModuleInstrumented(const load_command * first_lc)34868d75effSDimitry Andric static bool IsModuleInstrumented(const load_command *first_lc) {
34968d75effSDimitry Andric for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) {
35068d75effSDimitry Andric if (lc->cmd != LC_LOAD_DYLIB) continue;
35168d75effSDimitry Andric
35268d75effSDimitry Andric const dylib_command *dylib_lc = (const dylib_command *)lc;
35368d75effSDimitry Andric uint32_t dylib_name_offset = dylib_lc->dylib.name.offset;
35468d75effSDimitry Andric const char *dylib_name = ((const char *)dylib_lc) + dylib_name_offset;
35568d75effSDimitry Andric dylib_name = StripModuleName(dylib_name);
35668d75effSDimitry Andric if (dylib_name != 0 && (internal_strstr(dylib_name, "libclang_rt."))) {
35768d75effSDimitry Andric return true;
35868d75effSDimitry Andric }
35968d75effSDimitry Andric }
36068d75effSDimitry Andric return false;
36168d75effSDimitry Andric }
36268d75effSDimitry Andric
CurrentImageHeader()363*06c3fb27SDimitry Andric const ImageHeader *MemoryMappingLayout::CurrentImageHeader() {
36468d75effSDimitry Andric const mach_header *hdr = (data_.current_image == kDyldImageIdx)
36568d75effSDimitry Andric ? get_dyld_hdr()
36668d75effSDimitry Andric : _dyld_get_image_header(data_.current_image);
367*06c3fb27SDimitry Andric return (const ImageHeader *)hdr;
368*06c3fb27SDimitry Andric }
369*06c3fb27SDimitry Andric
Next(MemoryMappedSegment * segment)370*06c3fb27SDimitry Andric bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
371*06c3fb27SDimitry Andric for (; data_.current_image >= kDyldImageIdx; data_.current_image--) {
372*06c3fb27SDimitry Andric const mach_header *hdr = (const mach_header *)CurrentImageHeader();
37368d75effSDimitry Andric if (!hdr) continue;
37468d75effSDimitry Andric if (data_.current_load_cmd_count < 0) {
37568d75effSDimitry Andric // Set up for this image;
37668d75effSDimitry Andric data_.current_load_cmd_count = hdr->ncmds;
37768d75effSDimitry Andric data_.current_magic = hdr->magic;
37868d75effSDimitry Andric data_.current_filetype = hdr->filetype;
37968d75effSDimitry Andric data_.current_arch = ModuleArchFromCpuType(hdr->cputype, hdr->cpusubtype);
38068d75effSDimitry Andric switch (data_.current_magic) {
38168d75effSDimitry Andric #ifdef MH_MAGIC_64
38268d75effSDimitry Andric case MH_MAGIC_64: {
38368d75effSDimitry Andric data_.current_load_cmd_addr =
38468d75effSDimitry Andric (const char *)hdr + sizeof(mach_header_64);
38568d75effSDimitry Andric break;
38668d75effSDimitry Andric }
38768d75effSDimitry Andric #endif
38868d75effSDimitry Andric case MH_MAGIC: {
38968d75effSDimitry Andric data_.current_load_cmd_addr = (const char *)hdr + sizeof(mach_header);
39068d75effSDimitry Andric break;
39168d75effSDimitry Andric }
39268d75effSDimitry Andric default: {
39368d75effSDimitry Andric continue;
39468d75effSDimitry Andric }
39568d75effSDimitry Andric }
39668d75effSDimitry Andric FindUUID((const load_command *)data_.current_load_cmd_addr,
39768d75effSDimitry Andric data_.current_uuid);
39868d75effSDimitry Andric data_.current_instrumented = IsModuleInstrumented(
39968d75effSDimitry Andric (const load_command *)data_.current_load_cmd_addr);
40068d75effSDimitry Andric }
40168d75effSDimitry Andric
402*06c3fb27SDimitry Andric while (data_.current_load_cmd_count > 0) {
40368d75effSDimitry Andric switch (data_.current_magic) {
40468d75effSDimitry Andric // data_.current_magic may be only one of MH_MAGIC, MH_MAGIC_64.
40568d75effSDimitry Andric #ifdef MH_MAGIC_64
40668d75effSDimitry Andric case MH_MAGIC_64: {
40768d75effSDimitry Andric if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
40868d75effSDimitry Andric segment, segment->data_, &data_))
40968d75effSDimitry Andric return true;
41068d75effSDimitry Andric break;
41168d75effSDimitry Andric }
41268d75effSDimitry Andric #endif
41368d75effSDimitry Andric case MH_MAGIC: {
41468d75effSDimitry Andric if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
41568d75effSDimitry Andric segment, segment->data_, &data_))
41668d75effSDimitry Andric return true;
41768d75effSDimitry Andric break;
41868d75effSDimitry Andric }
41968d75effSDimitry Andric }
42068d75effSDimitry Andric }
42168d75effSDimitry Andric // If we get here, no more load_cmd's in this image talk about
42268d75effSDimitry Andric // segments. Go on to the next image.
423*06c3fb27SDimitry Andric data_.current_load_cmd_count = -1; // This will trigger loading next image
42468d75effSDimitry Andric }
42568d75effSDimitry Andric return false;
42668d75effSDimitry Andric }
42768d75effSDimitry Andric
DumpListOfModules(InternalMmapVectorNoCtor<LoadedModule> * modules)42868d75effSDimitry Andric void MemoryMappingLayout::DumpListOfModules(
42968d75effSDimitry Andric InternalMmapVectorNoCtor<LoadedModule> *modules) {
43068d75effSDimitry Andric Reset();
431fe6060f1SDimitry Andric InternalMmapVector<char> module_name(kMaxPathLength);
432fe6060f1SDimitry Andric MemoryMappedSegment segment(module_name.data(), module_name.size());
43368d75effSDimitry Andric MemoryMappedSegmentData data;
43468d75effSDimitry Andric segment.data_ = &data;
43568d75effSDimitry Andric while (Next(&segment)) {
43668d75effSDimitry Andric if (segment.filename[0] == '\0') continue;
43768d75effSDimitry Andric LoadedModule *cur_module = nullptr;
43868d75effSDimitry Andric if (!modules->empty() &&
43968d75effSDimitry Andric 0 == internal_strcmp(segment.filename, modules->back().full_name())) {
44068d75effSDimitry Andric cur_module = &modules->back();
44168d75effSDimitry Andric } else {
44268d75effSDimitry Andric modules->push_back(LoadedModule());
44368d75effSDimitry Andric cur_module = &modules->back();
44468d75effSDimitry Andric cur_module->set(segment.filename, segment.start, segment.arch,
44568d75effSDimitry Andric segment.uuid, data_.current_instrumented);
44668d75effSDimitry Andric }
44768d75effSDimitry Andric segment.AddAddressRanges(cur_module);
44868d75effSDimitry Andric }
44968d75effSDimitry Andric }
45068d75effSDimitry Andric
45168d75effSDimitry Andric } // namespace __sanitizer
45268d75effSDimitry Andric
45381ad6265SDimitry Andric #endif // SANITIZER_APPLE
454