forked from OSchip/llvm-project
[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:
parent
1a8fa8b431
commit
b97bcc4981
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
|
||||
namespace __sanitizer {
|
||||
|
||||
static const uptr kMaxNumberOfModules = 1 << 14;
|
||||
static const uptr kMaxTextSize = 64 * 1024;
|
||||
|
||||
struct CachedMapping {
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 { }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue