Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h @@ -646,18 +646,40 @@ return first; } +enum ModuleArch { + kModuleArchUnknown, + kModuleArchI386, + kModuleArchX86_64, + kModuleArchX86_64H, + kModuleArchARMV6, + kModuleArchARMV7, + kModuleArchARMV7S, + kModuleArchARMV7K, + kModuleArchARM64 +}; + +const uptr kModuleUUIDSize = 16; + // Represents a binary loaded into virtual memory (e.g. this can be an // executable or a shared object). class LoadedModule { public: - LoadedModule() : full_name_(nullptr), base_address_(0) { ranges_.clear(); } + LoadedModule() + : full_name_(nullptr), base_address_(0), arch_(kModuleArchUnknown) { + internal_memset(uuid_, 0, kModuleUUIDSize); + ranges_.clear(); + } void set(const char *module_name, uptr base_address); + void set(const char *module_name, uptr base_address, ModuleArch arch, + u8 uuid[kModuleUUIDSize]); void clear(); void addAddressRange(uptr beg, uptr end, bool executable); bool containsAddress(uptr address) const; const char *full_name() const { return full_name_; } uptr base_address() const { return base_address_; } + ModuleArch arch() const { return arch_; } + const u8 *uuid() const { return uuid_; } struct AddressRange { AddressRange *next; @@ -674,6 +696,8 @@ private: char *full_name_; // Owned. uptr base_address_; + ModuleArch arch_; + u8 uuid_[kModuleUUIDSize]; IntrusiveList ranges_; }; Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.cc @@ -259,9 +259,18 @@ base_address_ = base_address; } +void LoadedModule::set(const char *module_name, uptr base_address, + ModuleArch arch, u8 uuid[kModuleUUIDSize]) { + set(module_name, base_address); + arch_ = arch; + internal_memcpy(uuid_, uuid, sizeof(uuid_)); +} + void LoadedModule::clear() { InternalFree(full_name_); full_name_ = nullptr; + arch_ = kModuleArchUnknown; + internal_memset(uuid_, 0, kModuleUUIDSize); while (!ranges_.empty()) { AddressRange *r = ranges_.front(); ranges_.pop_front(); 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 @@ -35,8 +35,9 @@ public: explicit MemoryMappingLayout(bool cache_enabled); ~MemoryMappingLayout(); - bool Next(uptr *start, uptr *end, uptr *offset, - char filename[], uptr filename_size, uptr *protection); + bool Next(uptr *start, uptr *end, uptr *offset, char filename[], + uptr filename_size, uptr *protection, ModuleArch *arch = nullptr, + u8 *uuid = nullptr); void Reset(); // In some cases, e.g. when running under a sandbox on Linux, ASan is unable // to obtain the memory mappings. It should fall back to pre-cached data @@ -65,13 +66,15 @@ static ProcSelfMapsBuff cached_proc_self_maps_; static StaticSpinMutex cache_lock_; // protects cached_proc_self_maps_. # elif SANITIZER_MAC - template - bool NextSegmentLoad(uptr *start, uptr *end, uptr *offset, - char filename[], uptr filename_size, + template + bool NextSegmentLoad(uptr *start, uptr *end, uptr *offset, char filename[], + uptr filename_size, ModuleArch *arch, u8 *uuid, uptr *protection); int current_image_; u32 current_magic_; u32 current_filetype_; + ModuleArch current_arch_; + u8 current_uuid_[kModuleUUIDSize]; int current_load_cmd_count_; char *current_load_cmd_addr_; # endif Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc @@ -50,7 +50,9 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, char filename[], uptr filename_size, - uptr *protection) { + uptr *protection, ModuleArch *arch, u8 *uuid) { + CHECK(!arch && "not implemented"); + CHECK(!uuid && "not implemented"); char *last = proc_self_maps_.data + proc_self_maps_.len; if (current_ >= last) return false; uptr dummy; Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps_linux.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps_linux.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_procmaps_linux.cc @@ -28,7 +28,9 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, char filename[], uptr filename_size, - uptr *protection) { + uptr *protection, ModuleArch *arch, u8 *uuid) { + CHECK(!arch && "not implemented"); + CHECK(!uuid && "not implemented"); char *last = proc_self_maps_.data + proc_self_maps_.len; if (current_ >= last) return false; uptr dummy; 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 @@ -53,6 +53,8 @@ current_load_cmd_addr_ = 0; current_magic_ = 0; current_filetype_ = 0; + current_arch_ = kModuleArchUnknown; + internal_memset(current_uuid_, 0, kModuleUUIDSize); } // static @@ -71,11 +73,12 @@ // and returns the start and end addresses and file offset of the corresponding // segment. // Note that the segment addresses are not necessarily sorted. -template -bool MemoryMappingLayout::NextSegmentLoad( - uptr *start, uptr *end, uptr *offset, - char filename[], uptr filename_size, uptr *protection) { - const char* lc = current_load_cmd_addr_; +template +bool MemoryMappingLayout::NextSegmentLoad(uptr *start, uptr *end, uptr *offset, + char filename[], uptr filename_size, + ModuleArch *arch, u8 *uuid, + uptr *protection) { + const char *lc = current_load_cmd_addr_; current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize; if (((const load_command *)lc)->cmd == kLCSegment) { const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); @@ -97,14 +100,61 @@ internal_strncpy(filename, _dyld_get_image_name(current_image_), filename_size); } + if (arch) { + *arch = current_arch_; + } + if (uuid) { + internal_memcpy(uuid, current_uuid_, kModuleUUIDSize); + } return true; } return false; } +ModuleArch ModuleArchFromCpuType(cpu_type_t cputype, cpu_subtype_t cpusubtype) { + cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK; + switch (cputype) { + case CPU_TYPE_I386: + return kModuleArchI386; + case CPU_TYPE_X86_64: + if (cpusubtype == CPU_SUBTYPE_X86_64_ALL) return kModuleArchX86_64; + if (cpusubtype == CPU_SUBTYPE_X86_64_H) return kModuleArchX86_64H; + CHECK(0 && "Invalid subtype of x86_64"); + return kModuleArchUnknown; + case CPU_TYPE_ARM: + if (cpusubtype == CPU_SUBTYPE_ARM_V6) return kModuleArchARMV6; + if (cpusubtype == CPU_SUBTYPE_ARM_V7) return kModuleArchARMV7; + if (cpusubtype == CPU_SUBTYPE_ARM_V7S) return kModuleArchARMV7S; + if (cpusubtype == CPU_SUBTYPE_ARM_V7K) return kModuleArchARMV7K; + CHECK(0 && "Invalid subtype of ARM"); + return kModuleArchUnknown; + case CPU_TYPE_ARM64: + return kModuleArchARM64; + default: + CHECK(0 && "Invalid CPU type"); + return kModuleArchUnknown; + } +} + +static void FindUUID(const load_command *first_lc, u8 *uuid_output) { + const load_command *current_lc = first_lc; + while (1) { + if (current_lc->cmd == 0) return; + if (current_lc->cmd == LC_UUID) { + const uuid_command *uuid_lc = (const uuid_command *)current_lc; + const uint8_t *uuid = &uuid_lc->uuid[0]; + internal_memcpy(uuid_output, uuid, kModuleUUIDSize); + return; + } + + current_lc = + (const load_command *)(((char *)current_lc) + current_lc->cmdsize); + } +} + bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, char filename[], uptr filename_size, - uptr *protection) { + uptr *protection, ModuleArch *arch, u8 *uuid) { for (; current_image_ >= 0; current_image_--) { const mach_header* hdr = _dyld_get_image_header(current_image_); if (!hdr) continue; @@ -113,6 +163,7 @@ current_load_cmd_count_ = hdr->ncmds; current_magic_ = hdr->magic; current_filetype_ = hdr->filetype; + current_arch_ = ModuleArchFromCpuType(hdr->cputype, hdr->cpusubtype); switch (current_magic_) { #ifdef MH_MAGIC_64 case MH_MAGIC_64: { @@ -130,20 +181,24 @@ } } + FindUUID((const load_command *)current_load_cmd_addr_, ¤t_uuid_[0]); + for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) { switch (current_magic_) { // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64. #ifdef MH_MAGIC_64 case MH_MAGIC_64: { if (NextSegmentLoad( - start, end, offset, filename, filename_size, protection)) + start, end, offset, filename, filename_size, arch, uuid, + protection)) return true; break; } #endif case MH_MAGIC: { if (NextSegmentLoad( - start, end, offset, filename, filename_size, protection)) + start, end, offset, filename, filename_size, arch, uuid, + protection)) return true; break; } @@ -159,9 +214,11 @@ InternalMmapVector *modules) { Reset(); uptr cur_beg, cur_end, prot; + ModuleArch cur_arch; + u8 cur_uuid[kModuleUUIDSize]; InternalScopedString module_name(kMaxPathLength); for (uptr i = 0; Next(&cur_beg, &cur_end, 0, module_name.data(), - module_name.size(), &prot); + module_name.size(), &prot, &cur_arch, &cur_uuid[0]); i++) { const char *cur_name = module_name.data(); if (cur_name[0] == '\0') @@ -173,7 +230,7 @@ } else { modules->push_back(LoadedModule()); cur_module = &modules->back(); - cur_module->set(cur_name, cur_beg); + cur_module->set(cur_name, cur_beg, cur_arch, cur_uuid); } cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute); } Index: compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc +++ compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc @@ -52,5 +52,26 @@ EXPECT_TRUE(found); } +TEST(MemoryMapping, LoadedModuleArchAndUUID) { + if (SANITIZER_MAC) { + MemoryMappingLayout memory_mapping(false); + const uptr kMaxModules = 100; + InternalMmapVector modules(kMaxModules); + memory_mapping.DumpListOfModules(&modules); + for (uptr i = 0; i < modules.size(); ++i) { + ModuleArch arch = modules[i].arch(); + // Darwin unit tests are only run on i386/x86_64/x86_64h. + if (SANITIZER_WORDSIZE == 32) { + EXPECT_EQ(arch, kModuleArchI386); + } else if (SANITIZER_WORDSIZE == 64) { + EXPECT_TRUE(arch == kModuleArchX86_64 || arch == kModuleArchX86_64H); + } + const u8 *uuid = modules[i].uuid(); + u8 null_uuid[kModuleUUIDSize] = {0}; + EXPECT_NE(memcmp(null_uuid, uuid, kModuleUUIDSize), 0); + } + } +} + } // namespace __sanitizer #endif // !defined(_WIN32)