Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps.h =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps.h +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps.h @@ -37,9 +37,12 @@ static const uptr kProtectionExecute = 4; static const uptr kProtectionShared = 8; -struct MemoryMappedSegment { +struct MemoryMappedSegmentData; + +class MemoryMappedSegment { + public: MemoryMappedSegment(char *buff = nullptr, uptr size = 0) - : filename(buff), filename_size(size) {} + : filename(buff), filename_size(size), data_(nullptr) {} ~MemoryMappedSegment() {} bool IsReadable() const { return protection & kProtectionRead; } @@ -47,6 +50,8 @@ bool IsExecutable() const { return protection & kProtectionExecute; } bool IsShared() const { return protection & kProtectionShared; } + void AddAddressRanges(LoadedModule *module); + uptr start; uptr end; uptr offset; @@ -55,6 +60,12 @@ uptr protection; ModuleArch arch; u8 uuid[kModuleUUIDSize]; + + private: + friend class MemoryMappingLayout; + + // This field is assigned and owned by MemoryMappingLayout if needed + MemoryMappedSegmentData *data_; }; class MemoryMappingLayout { Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps_common.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -64,6 +64,10 @@ return ParseNumber(p, 16); } +void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { + module->addAddressRange(start, end, IsExecutable(), IsWritable()); +} + MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { ReadProcMaps(&proc_self_maps_); if (cache_enabled) { @@ -139,8 +143,7 @@ uptr base_address = (i ? segment.start : 0) - segment.offset; LoadedModule cur_module; cur_module.set(cur_name, base_address); - cur_module.addAddressRange(segment.start, segment.end, - segment.IsExecutable(), segment.IsWritable()); + segment.AddAddressRanges(&cur_module); modules->push_back(cur_module); } } Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps_mac.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -36,6 +36,48 @@ namespace __sanitizer { +// Contains information used to iterate through sections. +struct MemoryMappedSegmentData { + uptr nsects; + char *current_load_cmd_addr; + u32 lc_type; + uptr base_virt_addr; + uptr addr_mask; +}; + +template +static void NextSectionLoad(LoadedModule *module, MemoryMappedSegmentData *data, + bool isWritable) { + const Section *sc = (const Section *)data->current_load_cmd_addr; + data->current_load_cmd_addr += sizeof(Section); + + uptr sec_start = (sc->addr & data->addr_mask) + data->base_virt_addr; + uptr sec_end = sec_start + sc->size; + module->addAddressRange(sec_start, sec_end, /*executable=*/false, isWritable); +} + +void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { + // Don't iterate over sections when the caller hasn't set up the + // data pointer, when there are no sections, or when the segment + // is executable. Avoid iterating over executable sections because + // it will confuse libignore, and because the extra granularity + // of information is not needed by any sanitizers. + if (!data_ || !data_->nsects || IsExecutable()) { + module->addAddressRange(start, end, IsExecutable(), IsWritable()); + return; + } + + do { + if (data_->lc_type == LC_SEGMENT) { + NextSectionLoad(module, data_, IsWritable()); +#ifdef MH_MAGIC_64 + } else if (data_->lc_type == LC_SEGMENT_64) { + NextSectionLoad(module, data_, IsWritable()); +#endif + } + } while (--data_->nsects); +} + MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { Reset(); } @@ -144,19 +186,32 @@ if (((const load_command *)lc)->cmd == kLCSegment) { const SegmentCommand* sc = (const SegmentCommand *)lc; + uptr base_virt_addr, addr_mask; if (current_image_ == kDyldImageIdx) { + base_virt_addr = (uptr)get_dyld_hdr(); // vmaddr is masked with 0xfffff because on macOS versions < 10.12, // it contains an absolute address rather than an offset for dyld. // To make matters even more complicated, this absolute address // isn't actually the absolute segment address, but the offset portion // of the address is accurate when combined with the dyld base address, // and the mask will give just this offset. - segment->start = (sc->vmaddr & 0xfffff) + (uptr)get_dyld_hdr(); - segment->end = (sc->vmaddr & 0xfffff) + sc->vmsize + (uptr)get_dyld_hdr(); + addr_mask = 0xfffff; } else { - const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); - segment->start = sc->vmaddr + dlloff; - segment->end = sc->vmaddr + sc->vmsize + dlloff; + base_virt_addr = (uptr)_dyld_get_image_vmaddr_slide(current_image_); + addr_mask = ~0; + } + segment->start = (sc->vmaddr & addr_mask) + base_virt_addr; + segment->end = segment->start + sc->vmsize; + + // Most callers don't need section information, so only fill this struct + // when required. + if (segment->data_) { + segment->data_->nsects = sc->nsects; + segment->data_->current_load_cmd_addr = + (char *)lc + sizeof(SegmentCommand); + segment->data_->lc_type = kLCSegment; + segment->data_->base_virt_addr = base_virt_addr; + segment->data_->addr_mask = addr_mask; } // Return the initial protection. @@ -292,7 +347,9 @@ Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), kMaxPathLength); - for (uptr i = 0; Next(&segment); i++) { + MemoryMappedSegmentData data; + segment.data_ = &data; + while (Next(&segment)) { if (segment.filename[0] == '\0') continue; LoadedModule *cur_module = nullptr; if (!modules->empty() && @@ -304,8 +361,7 @@ cur_module->set(segment.filename, segment.start, segment.arch, segment.uuid, current_instrumented_); } - cur_module->addAddressRange(segment.start, segment.end, - segment.IsExecutable(), segment.IsWritable()); + segment.AddAddressRanges(cur_module); } }