Index: sanitizer_common.h =================================================================== --- sanitizer_common.h +++ sanitizer_common.h @@ -39,6 +39,9 @@ const uptr kMaxPathLength = 4096; +// 16K loaded modules should be enough for everyone. +static const uptr kMaxNumberOfModules = 1 << 14; + const uptr kMaxThreadStackSize = 1 << 30; // 1Gb extern const char *SanitizerToolName; // Can be changed by the tool. @@ -548,8 +551,8 @@ // executable or a shared object). class LoadedModule { public: - LoadedModule() : full_name_(nullptr), base_address_(0) {} - LoadedModule(const char *module_name, uptr base_address); + LoadedModule() : full_name_(nullptr), base_address_(0) { ranges_.clear(); } + void set(const char *module_name, uptr base_address); void clear(); void addAddressRange(uptr beg, uptr end, bool executable); bool containsAddress(uptr address) const; Index: sanitizer_common.cc =================================================================== --- sanitizer_common.cc +++ sanitizer_common.cc @@ -250,14 +250,15 @@ } #endif -LoadedModule::LoadedModule(const char *module_name, uptr base_address) { +void LoadedModule::set(const char *module_name, uptr base_address) { + clear(); full_name_ = internal_strdup(module_name); base_address_ = base_address; - ranges_.clear(); } void LoadedModule::clear() { InternalFree(full_name_); + full_name_ = nullptr; while (!ranges_.empty()) { AddressRange *r = ranges_.front(); ranges_.pop_front(); Index: sanitizer_coverage_mapping_libcdep.cc =================================================================== --- sanitizer_coverage_mapping_libcdep.cc +++ sanitizer_coverage_mapping_libcdep.cc @@ -35,7 +35,6 @@ namespace __sanitizer { -static const uptr kMaxNumberOfModules = 1 << 14; static const uptr kMaxTextSize = 64 * 1024; struct CachedMapping { Index: sanitizer_linux_libcdep.cc =================================================================== --- sanitizer_linux_libcdep.cc +++ sanitizer_linux_libcdep.cc @@ -436,9 +436,8 @@ return 0; if (data->filter && !data->filter(module_name.data())) return 0; - void *mem = &data->modules[data->current_n]; - LoadedModule *cur_module = new(mem) LoadedModule(module_name.data(), - info->dlpi_addr); + LoadedModule &cur_module = data->modules[data->current_n]; + cur_module.set(module_name.data(), info->dlpi_addr); data->current_n++; for (int i = 0; i < info->dlpi_phnum; i++) { const Elf_Phdr *phdr = &info->dlpi_phdr[i]; @@ -446,7 +445,7 @@ uptr cur_beg = info->dlpi_addr + phdr->p_vaddr; uptr cur_end = cur_beg + phdr->p_memsz; bool executable = phdr->p_flags & PF_X; - cur_module->addAddressRange(cur_beg, cur_end, executable); + cur_module.addAddressRange(cur_beg, cur_end, executable); } } return 0; Index: sanitizer_procmaps_common.cc =================================================================== --- sanitizer_procmaps_common.cc +++ sanitizer_procmaps_common.cc @@ -130,7 +130,6 @@ continue; if (filter && !filter(cur_name)) continue; - void *mem = &modules[n_modules]; // Don't subtract 'cur_beg' from the first entry: // * If a binary is compiled w/o -pie, then the first entry in // process maps is likely the binary itself (all dynamic libs @@ -143,8 +142,9 @@ // shadow memory of the tool), so the module can't be the // first entry. uptr base_address = (i ? cur_beg : 0) - cur_offset; - LoadedModule *cur_module = new(mem) LoadedModule(cur_name, base_address); - cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute); + LoadedModule &cur_module = modules[n_modules]; + cur_module.set(cur_name, base_address); + cur_module.addAddressRange(cur_beg, cur_end, prot & kProtectionExecute); n_modules++; } return n_modules; Index: sanitizer_procmaps_mac.cc =================================================================== --- sanitizer_procmaps_mac.cc +++ sanitizer_procmaps_mac.cc @@ -176,8 +176,8 @@ 0 == internal_strcmp(cur_name, modules[n_modules - 1].full_name())) { cur_module = &modules[n_modules - 1]; } else { - void *mem = &modules[n_modules]; - cur_module = new(mem) LoadedModule(cur_name, cur_beg); + cur_module = &modules[n_modules]; + cur_module->set(cur_name, cur_beg); n_modules++; } cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute); Index: sanitizer_symbolizer.h =================================================================== --- sanitizer_symbolizer.h +++ sanitizer_symbolizer.h @@ -137,10 +137,18 @@ /// Platform-specific function for creating a Symbolizer object. static Symbolizer *PlatformInit(); - virtual bool PlatformFindModuleNameAndOffsetForAddress( - uptr address, const char **module_name, uptr *module_offset) { + bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name, + uptr *module_offset); + LoadedModule *FindModuleForAddress(uptr address); + virtual uptr PlatformGetListOfModules(LoadedModule *modules, + uptr max_modules) { UNIMPLEMENTED(); } + LoadedModule modules_[kMaxNumberOfModules]; + uptr n_modules_; + // If stale, need to reload the modules before looking up addresses. + bool modules_fresh_; + // Platform-specific default demangler, must not return nullptr. virtual const char *PlatformDemangle(const char *name) { UNIMPLEMENTED(); } virtual void PlatformPrepareForSandboxing() { UNIMPLEMENTED(); } Index: sanitizer_symbolizer.cc =================================================================== --- sanitizer_symbolizer.cc +++ sanitizer_symbolizer.cc @@ -95,8 +95,47 @@ return last_match_; } +bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, + const char **module_name, + uptr *module_offset) { + LoadedModule *module = FindModuleForAddress(address); + if (module == 0) + return false; + *module_name = module->full_name(); + *module_offset = address - module->base_address(); + return true; +} + +LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { + bool modules_were_reloaded = false; + if (!modules_fresh_) { + for (uptr i = 0; i < n_modules_; i++) + modules_[i].clear(); + n_modules_ = PlatformGetListOfModules(modules_, kMaxNumberOfModules); + CHECK_GT(n_modules_, 0); + CHECK_LT(n_modules_, kMaxNumberOfModules); + modules_fresh_ = true; + modules_were_reloaded = true; + } + for (uptr i = 0; i < n_modules_; i++) { + if (modules_[i].containsAddress(address)) { + return &modules_[i]; + } + } + // Reload the modules and look up again, if we haven't tried it yet. + if (!modules_were_reloaded) { + // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors. + // It's too aggressive to reload the list of modules each time we fail + // to find a module for a given address. + modules_fresh_ = false; + return FindModuleForAddress(address); + } + return 0; +} + Symbolizer::Symbolizer(IntrusiveList tools) - : module_names_(&mu_), tools_(tools), start_hook_(0), end_hook_(0) {} + : module_names_(&mu_), n_modules_(0), modules_fresh_(false), tools_(tools), + start_hook_(0), end_hook_(0) {} Symbolizer::SymbolizerScope::SymbolizerScope(const Symbolizer *sym) : sym_(sym) { @@ -114,8 +153,7 @@ const char *module_name; uptr module_offset; SymbolizedStack *res = SymbolizedStack::New(addr); - if (!PlatformFindModuleNameAndOffsetForAddress(addr, &module_name, - &module_offset)) + if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset)) return res; // Always fill data about module name and offset. res->info.FillModuleInfo(module_name, module_offset); @@ -133,8 +171,7 @@ BlockingMutexLock l(&mu_); const char *module_name; uptr module_offset; - if (!PlatformFindModuleNameAndOffsetForAddress(addr, &module_name, - &module_offset)) + if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset)) return false; info->Clear(); info->module = internal_strdup(module_name); @@ -153,8 +190,8 @@ uptr *module_address) { BlockingMutexLock l(&mu_); const char *internal_module_name = nullptr; - if (!PlatformFindModuleNameAndOffsetForAddress(pc, &internal_module_name, - module_address)) + if (!FindModuleNameAndOffsetForAddress(pc, &internal_module_name, + module_address)) return false; if (module_name) Index: sanitizer_symbolizer_posix_libcdep.cc =================================================================== --- sanitizer_symbolizer_posix_libcdep.cc +++ sanitizer_symbolizer_posix_libcdep.cc @@ -352,9 +352,14 @@ class POSIXSymbolizer : public Symbolizer { public: explicit POSIXSymbolizer(IntrusiveList tools) - : Symbolizer(tools), n_modules_(0), modules_fresh_(false) {} + : Symbolizer(tools) {} private: + uptr PlatformGetListOfModules(LoadedModule *modules, + uptr max_modules) override { + return ::GetListOfModules(modules, max_modules, /* filter */ nullptr); + } + const char *PlatformDemangle(const char *name) override { return DemangleCXXABI(name); } @@ -365,52 +370,6 @@ CacheBinaryName(); #endif } - - LoadedModule *FindModuleForAddress(uptr address) { - bool modules_were_reloaded = false; - if (!modules_fresh_) { - for (uptr i = 0; i < n_modules_; i++) - modules_[i].clear(); - n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts, - /* filter */ 0); - CHECK_GT(n_modules_, 0); - CHECK_LT(n_modules_, kMaxNumberOfModuleContexts); - modules_fresh_ = true; - modules_were_reloaded = true; - } - for (uptr i = 0; i < n_modules_; i++) { - if (modules_[i].containsAddress(address)) { - return &modules_[i]; - } - } - // Reload the modules and look up again, if we haven't tried it yet. - if (!modules_were_reloaded) { - // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors. - // It's too aggressive to reload the list of modules each time we fail - // to find a module for a given address. - modules_fresh_ = false; - return FindModuleForAddress(address); - } - return 0; - } - - bool PlatformFindModuleNameAndOffsetForAddress(uptr address, - const char **module_name, - uptr *module_offset) override { - LoadedModule *module = FindModuleForAddress(address); - if (module == 0) - return false; - *module_name = module->full_name(); - *module_offset = address - module->base_address(); - return true; - } - - // 16K loaded modules should be enough for everyone. - static const uptr kMaxNumberOfModuleContexts = 1 << 14; - LoadedModule modules_[kMaxNumberOfModuleContexts]; - uptr n_modules_; - // If stale, need to reload the modules before looking up addresses. - bool modules_fresh_; }; static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) { Index: sanitizer_symbolizer_win.cc =================================================================== --- sanitizer_symbolizer_win.cc +++ sanitizer_symbolizer_win.cc @@ -129,21 +129,6 @@ return name; } -bool FindModuleNameAndOffsetForAddress(uptr addr, const char **module_name, - uptr *module_offset) { - InitializeDbgHelpIfNeeded(); - - IMAGEHLP_MODULE64 mod_info; - internal_memset(&mod_info, 0, sizeof(mod_info)); - mod_info.SizeOfStruct = sizeof(mod_info); - if (SymGetModuleInfo64(GetCurrentProcess(), addr, &mod_info)) { - *module_name = mod_info.ImageName; - *module_offset = addr - (uptr)mod_info.BaseOfImage; - return true; - } - return false; -} - // TODO(kuba.brecka): To be merged with POSIXSymbolizer. class WinSymbolizer : public Symbolizer { public: @@ -151,10 +136,9 @@ : Symbolizer(tools) {} private: - bool PlatformFindModuleNameAndOffsetForAddress( - uptr addr, const char **module_name, uptr *module_offset) override { - return ::FindModuleNameAndOffsetForAddress(addr, module_name, - module_offset); + uptr PlatformGetListOfModules(LoadedModule *modules, + uptr max_modules) override { + return ::GetListOfModules(modules, max_modules, /* filter */ nullptr); } const char *PlatformDemangle(const char *name) override { return name; } void PlatformPrepareForSandboxing() override { } Index: sanitizer_win.cc =================================================================== --- sanitizer_win.cc +++ sanitizer_win.cc @@ -209,76 +209,46 @@ namespace { struct ModuleInfo { - HMODULE handle; + const char *filepath; uptr base_address; uptr end_address; }; int CompareModulesBase(const void *pl, const void *pr) { - const ModuleInfo &l = *(ModuleInfo *)pl, &r = *(ModuleInfo *)pr; - if (l.base_address < r.base_address) + const ModuleInfo *l = (ModuleInfo *)pl, *r = (ModuleInfo *)pr; + if (l->base_address < r->base_address) return -1; - return l.base_address > r.base_address; + return l->base_address > r->base_address; } } // namespace #ifndef SANITIZER_GO void DumpProcessMap() { Report("Dumping process modules:\n"); - HANDLE cur_process = GetCurrentProcess(); - - // Query the list of modules. Start by assuming there are no more than 256 - // modules and retry if that's not sufficient. - ModuleInfo *modules; - size_t num_modules; - { - HMODULE *hmodules = 0; - uptr modules_buffer_size = sizeof(HMODULE) * 256; - DWORD bytes_required; - while (!hmodules) { - hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__); - CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size, - &bytes_required)); - if (bytes_required > modules_buffer_size) { - // Either there turned out to be more than 256 hmodules, or new hmodules - // could have loaded since the last try. Retry. - UnmapOrDie(hmodules, modules_buffer_size); - hmodules = 0; - modules_buffer_size = bytes_required; - } - } + InternalScopedBuffer modules(kMaxNumberOfModules); + uptr num_modules = + GetListOfModules(modules.data(), kMaxNumberOfModules, nullptr); - num_modules = bytes_required / sizeof(HMODULE); - modules = - (ModuleInfo *)MmapOrDie(num_modules * sizeof(ModuleInfo), __FUNCTION__); - for (size_t i = 0; i < num_modules; ++i) { - modules[i].handle = hmodules[i]; - MODULEINFO mi; - if (!GetModuleInformation(cur_process, hmodules[i], &mi, sizeof(mi))) - continue; - modules[i].base_address = (uptr)mi.lpBaseOfDll; - modules[i].end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage; - } - UnmapOrDie(hmodules, modules_buffer_size); + InternalScopedBuffer module_infos(num_modules); + for (size_t i = 0; i < num_modules; ++i) { + module_infos[i].filepath = modules[i].full_name(); + module_infos[i].base_address = modules[i].base_address(); + module_infos[i].end_address = modules[i].ranges().next()->end; } - - qsort(modules, num_modules, sizeof(ModuleInfo), CompareModulesBase); + qsort(module_infos.data(), num_modules, sizeof(ModuleInfo), + CompareModulesBase); for (size_t i = 0; i < num_modules; ++i) { - const ModuleInfo &mi = modules[i]; - char module_name[MAX_PATH]; - bool got_module_name = GetModuleFileNameA( - mi.handle, module_name, sizeof(module_name)); + const ModuleInfo &mi = module_infos[i]; if (mi.end_address != 0) { Printf("\t%p-%p %s\n", mi.base_address, mi.end_address, - got_module_name ? module_name : "[no name]"); - } else if (got_module_name) { - Printf("\t??\?-??? %s\n", module_name); + mi.filepath[0] ? mi.filepath : "[no name]"); + } else if (mi.filepath) { + Printf("\t??\?-??? %s\n", mi.filepath); } else { Printf("\t???\n"); } } - UnmapOrDie(modules, num_modules * sizeof(ModuleInfo)); } #endif @@ -349,7 +319,56 @@ uptr GetListOfModules(LoadedModule *modules, uptr max_modules, string_predicate_t filter) { - UNIMPLEMENTED(); + HANDLE cur_process = GetCurrentProcess(); + + // Query the list of modules. Start by assuming there are no more than 256 + // modules and retry if that's not sufficient. + HMODULE *hmodules = 0; + uptr modules_buffer_size = sizeof(HMODULE) * 256; + DWORD bytes_required; + while (!hmodules) { + hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__); + CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size, + &bytes_required)); + if (bytes_required > modules_buffer_size) { + // Either there turned out to be more than 256 hmodules, or new hmodules + // could have loaded since the last try. Retry. + UnmapOrDie(hmodules, modules_buffer_size); + hmodules = 0; + modules_buffer_size = bytes_required; + } + } + + // |num_modules| is the number of modules actually present, + // |count| is the number of modules we return. + size_t nun_modules = bytes_required / sizeof(HMODULE), + count = 0; + for (size_t i = 0; i < nun_modules && count < max_modules; ++i) { + HMODULE handle = hmodules[i]; + MODULEINFO mi; + if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi))) + continue; + + char module_name[MAX_PATH]; + bool got_module_name = + GetModuleFileNameA(handle, module_name, sizeof(module_name)); + if (!got_module_name) + module_name[0] = '\0'; + + if (filter && !filter(module_name)) + continue; + + uptr base_address = (uptr)mi.lpBaseOfDll; + uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage; + LoadedModule &cur_module = modules[count]; + cur_module.set(module_name, base_address); + // We add the whole module as one single address range. + cur_module.addAddressRange(base_address, end_address, /*executable*/ true); + count++; + } + UnmapOrDie(hmodules, modules_buffer_size); + + return count; }; #ifndef SANITIZER_GO Index: tests/sanitizer_procmaps_test.cc =================================================================== --- tests/sanitizer_procmaps_test.cc +++ tests/sanitizer_procmaps_test.cc @@ -37,8 +37,7 @@ const char *binary_name = last_slash ? last_slash + 1 : argv0; MemoryMappingLayout memory_mapping(false); const uptr kMaxModules = 100; - LoadedModule *modules = - (LoadedModule *)malloc(kMaxModules * sizeof(LoadedModule)); + LoadedModule modules[kMaxModules]; uptr n_modules = memory_mapping.DumpListOfModules(modules, kMaxModules, 0); EXPECT_GT(n_modules, 0U); bool found = false; @@ -51,7 +50,6 @@ modules[i].clear(); } EXPECT_TRUE(found); - free(modules); } } // namespace __sanitizer