[ASan] Unify handling of loaded modules between POSIX and Windows

Reviewed at http://reviews.llvm.org/D8805

llvm-svn: 234150
This commit is contained in:
Timur Iskhodzhanov 2015-04-06 12:49:30 +00:00
parent 1a8fa8b431
commit b97bcc4981
12 changed files with 150 additions and 140 deletions

View File

@ -250,14 +250,15 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info) {
}
#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();

View File

@ -39,6 +39,9 @@ const uptr kWordSizeInBits = 8 * kWordSize;
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 @@ uptr InternalBinarySearch(const Container &v, uptr first, uptr last,
// 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;

View File

@ -35,7 +35,6 @@
namespace __sanitizer {
static const uptr kMaxNumberOfModules = 1 << 14;
static const uptr kMaxTextSize = 64 * 1024;
struct CachedMapping {

View File

@ -436,9 +436,8 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
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];

View File

@ -130,7 +130,6 @@ uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
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,7 +142,8 @@ uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
// 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);
LoadedModule *cur_module = &modules[n_modules];
cur_module->set(cur_name, base_address);
cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
n_modules++;
}

View File

@ -171,13 +171,13 @@ uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
continue;
if (filter && !filter(cur_name))
continue;
LoadedModule *cur_module = 0;
LoadedModule *cur_module = nullptr;
if (n_modules > 0 &&
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);

View File

@ -95,8 +95,47 @@ const char *Symbolizer::ModuleNameOwner::GetOwnedCopy(const char *str) {
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<SymbolizerTool> 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 @@ SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
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 @@ bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
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 @@ bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
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)

View File

@ -137,10 +137,21 @@ class Symbolizer {
/// 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);
// FIXME: get rid of this virtual method, just use GetListOfModules directly.
// The only reason we don't do it right away is that GetListOfModules is
// currently implemented in a libcdep file.
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(); }

View File

@ -352,9 +352,14 @@ class InternalSymbolizer : public SymbolizerTool {
class POSIXSymbolizer : public Symbolizer {
public:
explicit POSIXSymbolizer(IntrusiveList<SymbolizerTool> 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 @@ class POSIXSymbolizer : public Symbolizer {
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) {

View File

@ -129,21 +129,6 @@ const char *WinSymbolizerTool::Demangle(const char *name) {
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 @@ class WinSymbolizer : public Symbolizer {
: 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 { }

View File

@ -209,76 +209,46 @@ u32 GetUid() {
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();
InternalScopedBuffer<LoadedModule> modules(kMaxNumberOfModules);
uptr num_modules =
GetListOfModules(modules.data(), kMaxNumberOfModules, nullptr);
// 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;
}
}
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<ModuleInfo> 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 @@ void Abort() {
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

View File

@ -37,8 +37,7 @@ TEST(MemoryMappingLayout, DumpListOfModules) {
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 @@ TEST(MemoryMappingLayout, DumpListOfModules) {
modules[i].clear();
}
EXPECT_TRUE(found);
free(modules);
}
} // namespace __sanitizer