Index: lib/asan/asan_rtl.cc =================================================================== --- lib/asan/asan_rtl.cc +++ lib/asan/asan_rtl.cc @@ -46,6 +46,7 @@ // Don't die twice - run a busy loop. while (1) { } } + if (common_flags()->print_module_map >= 1) PrintModuleMap(); if (flags()->sleep_before_dying) { Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying); SleepForSeconds(flags()->sleep_before_dying); Index: lib/sanitizer_common/sanitizer_common.h =================================================================== --- lib/sanitizer_common/sanitizer_common.h +++ lib/sanitizer_common/sanitizer_common.h @@ -283,6 +283,7 @@ void CacheBinaryName(); void DisableCoreDumperIfNecessary(); void DumpProcessMap(); +void PrintModuleMap(); bool FileExists(const char *filename); const char *GetEnv(const char *name); bool SetEnv(const char *name, const char *value); @@ -658,6 +659,30 @@ kModuleArchARM64 }; +inline const char *ModuleArchToString(ModuleArch arch) { + switch (arch) { + case kModuleArchUnknown: + return ""; + case kModuleArchI386: + return "i386"; + case kModuleArchX86_64: + return "x86_64"; + case kModuleArchX86_64H: + return "x86_64h"; + case kModuleArchARMV6: + return "armv6"; + case kModuleArchARMV7: + return "armv7"; + case kModuleArchARMV7S: + return "armv7s"; + case kModuleArchARMV7K: + return "armv7k"; + case kModuleArchARM64: + return "arm64"; + } + CHECK(0 && "Invalid module arch"); +} + const uptr kModuleUUIDSize = 16; // Represents a binary loaded into virtual memory (e.g. this can be an @@ -665,7 +690,10 @@ class LoadedModule { public: LoadedModule() - : full_name_(nullptr), base_address_(0), arch_(kModuleArchUnknown) { + : full_name_(nullptr), + base_address_(0), + max_executable_address_(0), + arch_(kModuleArchUnknown) { internal_memset(uuid_, 0, kModuleUUIDSize); ranges_.clear(); } @@ -678,6 +706,7 @@ const char *full_name() const { return full_name_; } uptr base_address() const { return base_address_; } + uptr max_executable_address() const { return max_executable_address_; } ModuleArch arch() const { return arch_; } const u8 *uuid() const { return uuid_; } @@ -696,6 +725,7 @@ private: char *full_name_; // Owned. uptr base_address_; + uptr max_executable_address_; ModuleArch arch_; u8 uuid_[kModuleUUIDSize]; IntrusiveList ranges_; Index: lib/sanitizer_common/sanitizer_common.cc =================================================================== --- lib/sanitizer_common/sanitizer_common.cc +++ lib/sanitizer_common/sanitizer_common.cc @@ -268,6 +268,8 @@ void LoadedModule::clear() { InternalFree(full_name_); + base_address_ = 0; + max_executable_address_ = 0; full_name_ = nullptr; arch_ = kModuleArchUnknown; internal_memset(uuid_, 0, kModuleUUIDSize); @@ -282,6 +284,8 @@ void *mem = InternalAlloc(sizeof(AddressRange)); AddressRange *r = new(mem) AddressRange(beg, end, executable); ranges_.push_back(r); + if (executable && end > max_executable_address_) + max_executable_address_ = end; } bool LoadedModule::containsAddress(uptr address) const { Index: lib/sanitizer_common/sanitizer_flags.inc =================================================================== --- lib/sanitizer_common/sanitizer_flags.inc +++ lib/sanitizer_common/sanitizer_flags.inc @@ -74,6 +74,9 @@ COMMON_FLAG(bool, print_summary, true, "If false, disable printing error summaries in addition to error " "reports.") +COMMON_FLAG(int, print_module_map, 0, + "OS X only. 0 = don't print, 1 = print only once before process " + "exits, 2 = print after each report.") COMMON_FLAG(bool, check_printf, true, "Check printf arguments.") COMMON_FLAG(bool, handle_segv, true, "If set, registers the tool's custom SIGSEGV/SIGBUS handler.") Index: lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux.cc +++ lib/sanitizer_common/sanitizer_linux.cc @@ -1393,6 +1393,8 @@ // No need to re-exec on Linux. } +void PrintModuleMap() { } + uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding) { UNREACHABLE("FindAvailableMemoryRange is not available"); return 0; Index: lib/sanitizer_common/sanitizer_mac.cc =================================================================== --- lib/sanitizer_common/sanitizer_mac.cc +++ lib/sanitizer_common/sanitizer_mac.cc @@ -52,6 +52,7 @@ #endif #include +#include #include // for dladdr() #include #include @@ -845,6 +846,41 @@ # undef DUMPREG } +static inline bool CompareBaseAddress(const LoadedModule &a, + const LoadedModule &b) { + return a.base_address() < b.base_address(); +} + +void FormatUUID(char *out, uptr size, const u8 *uuid) { + internal_snprintf(out, size, + "<%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x%02x%02x%02x%02x>", + uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], + uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], + uuid[14], uuid[15]); + // Now convert to uppercase. + while (*out) { + *out = toupper(*out); + out++; + } +} + +void PrintModuleMap() { + Printf("Process module map:\n"); + MemoryMappingLayout memory_mapping(false); + InternalMmapVector modules(/*initial_capacity*/ 128); + memory_mapping.DumpListOfModules(&modules); + InternalSort(&modules, modules.size(), CompareBaseAddress); + for (uptr i = 0; i < modules.size(); ++i) { + char uuid_str[128]; + FormatUUID(uuid_str, sizeof(uuid_str), modules[i].uuid()); + Printf("0x%llx-0x%llx %s (%s) %s\n", modules[i].base_address(), + modules[i].max_executable_address(), modules[i].full_name(), + ModuleArchToString(modules[i].arch()), uuid_str); + } + Printf("End of module map.\n"); +} + } // namespace __sanitizer #endif // SANITIZER_MAC Index: lib/sanitizer_common/sanitizer_win.cc =================================================================== --- lib/sanitizer_common/sanitizer_win.cc +++ lib/sanitizer_common/sanitizer_win.cc @@ -373,6 +373,8 @@ } #endif +void PrintModuleMap() { } + void DisableCoreDumperIfNecessary() { // Do nothing. } Index: lib/tsan/rtl/tsan_report.cc =================================================================== --- lib/tsan/rtl/tsan_report.cc +++ lib/tsan/rtl/tsan_report.cc @@ -358,6 +358,8 @@ ReportErrorSummary(rep_typ_str, frame->info); } + if (common_flags()->print_module_map == 2) PrintModuleMap(); + Printf("==================\n"); } Index: lib/tsan/rtl/tsan_rtl.cc =================================================================== --- lib/tsan/rtl/tsan_rtl.cc +++ lib/tsan/rtl/tsan_rtl.cc @@ -404,6 +404,8 @@ int Finalize(ThreadState *thr) { bool failed = false; + if (common_flags()->print_module_map == 1) PrintModuleMap(); + if (flags()->atexit_sleep_ms > 0 && ThreadCount(thr) > 1) SleepForMillis(flags()->atexit_sleep_ms);