diff options
author | Francis Ricci <francisjricci@gmail.com> | 2017-09-28 16:58:35 +0000 |
---|---|---|
committer | Francis Ricci <francisjricci@gmail.com> | 2017-09-28 16:58:35 +0000 |
commit | 81f388fe570e5b6460dd5bc9b9a36b72714eeb68 (patch) | |
tree | 52a34797d60ba30e42319e7b7c934177354b1de3 /lib | |
parent | 4d153fb22be7ea0f60799fb5d46de7473e8b1d7d (diff) |
Add support for custom loaders to the sanitizer symbolizer
Summary:
Adds a fallback mode to procmaps when the symbolizer
fails to locate a module for a given address by using
dl_iterate_phdr.
Reviewers: kubamracek, rnk, vitalybuka, eugenis
Reviewed By: eugenis
Subscribers: srhines, llvm-commits
Differential Revision: https://reviews.llvm.org/D37269
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@314431 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/sanitizer_common/sanitizer_common.h | 10 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_linux_libcdep.cc | 39 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_mac.cc | 4 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_procmaps.h | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_procmaps_common.cc | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_procmaps_mac.cc | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_symbolizer.h | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc | 46 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_win.cc | 6 |
9 files changed, 80 insertions, 33 deletions
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 47b02b149..ee5eca516 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -727,9 +727,10 @@ class LoadedModule { // filling this information. class ListOfModules { public: - ListOfModules() : modules_(kInitialCapacity) {} + ListOfModules() : initialized(false) {} ~ListOfModules() { clear(); } void init(); + void fallbackInit(); // Uses fallback init if available, otherwise clears const LoadedModule *begin() const { return modules_.begin(); } LoadedModule *begin() { return modules_.begin(); } const LoadedModule *end() const { return modules_.end(); } @@ -745,10 +746,15 @@ class ListOfModules { for (auto &module : modules_) module.clear(); modules_.clear(); } + void clearOrInit() { + initialized ? clear() : modules_.Initialize(kInitialCapacity); + initialized = true; + } - InternalMmapVector<LoadedModule> modules_; + InternalMmapVectorNoCtor<LoadedModule> modules_; // We rarely have more than 16K loaded modules. static const uptr kInitialCapacity = 1 << 14; + bool initialized; }; // Callback type for iterating over a set of memory ranges. diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 11d8b3ac0..f28d3e86b 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -26,6 +26,7 @@ #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" +#include "sanitizer_symbolizer.h" #include <dlfcn.h> // for dlsym() #include <link.h> @@ -424,7 +425,7 @@ typedef ElfW(Phdr) Elf_Phdr; # endif struct DlIteratePhdrData { - InternalMmapVector<LoadedModule> *modules; + InternalMmapVectorNoCtor<LoadedModule> *modules; bool first; }; @@ -462,21 +463,37 @@ extern "C" __attribute__((weak)) int dl_iterate_phdr( int (*)(struct dl_phdr_info *, size_t, void *), void *); #endif -void ListOfModules::init() { - clear(); +static bool requiresProcmaps() { #if SANITIZER_ANDROID && __ANDROID_API__ <= 22 - u32 api_level = AndroidGetApiLevel(); // Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken. // The runtime check allows the same library to work with // both K and L (and future) Android releases. - if (api_level <= ANDROID_LOLLIPOP_MR1) { // L or earlier - MemoryMappingLayout memory_mapping(false); - memory_mapping.DumpListOfModules(&modules_); - return; - } + return AndroidGetApiLevel() <= ANDROID_LOLLIPOP_MR1; +#else + return false; #endif - DlIteratePhdrData data = {&modules_, true}; - dl_iterate_phdr(dl_iterate_phdr_cb, &data); +} + +static void procmapsInit(InternalMmapVectorNoCtor<LoadedModule> *modules) { + MemoryMappingLayout memory_mapping(false); + memory_mapping.DumpListOfModules(modules); +} + +void ListOfModules::init() { + clearOrInit(); + if (requiresProcmaps()) { + procmapsInit(&modules_); + } else { + DlIteratePhdrData data = {&modules_, true}; + dl_iterate_phdr(dl_iterate_phdr_cb, &data); + } +} + +// When a custom loader is used, dl_iterate_phdr may not contain the full +// list of modules. Allow callers to fall back to using procmaps. +void ListOfModules::fallbackInit() { + clearOrInit(); + if (!requiresProcmaps()) procmapsInit(&modules_); } // getrusage does not give us the current RSS, only the max RSS. diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 1570ae277..9fead91b9 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -411,11 +411,13 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, } void ListOfModules::init() { - clear(); + clearOrInit(); MemoryMappingLayout memory_mapping(false); memory_mapping.DumpListOfModules(&modules_); } +void ListOfModules::fallbackInit() { clear(); } + static HandleSignalMode GetHandleSignalModeImpl(int signum) { switch (signum) { case SIGABRT: diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 96d0b2f9d..d462ad841 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -76,7 +76,7 @@ class MemoryMappingLayout { static void CacheMemoryMappings(); // Adds all mapped objects into a vector. - void DumpListOfModules(InternalMmapVector<LoadedModule> *modules); + void DumpListOfModules(InternalMmapVectorNoCtor<LoadedModule> *modules); private: void LoadFromCache(); diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index 30663e8c6..b9298d4cc 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -120,7 +120,7 @@ void MemoryMappingLayout::LoadFromCache() { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVector<LoadedModule> *modules) { + InternalMmapVectorNoCtor<LoadedModule> *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), module_name.size()); diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 786876f04..3b98ff095 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -353,7 +353,7 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { } void MemoryMappingLayout::DumpListOfModules( - InternalMmapVector<LoadedModule> *modules) { + InternalMmapVectorNoCtor<LoadedModule> *modules) { Reset(); InternalScopedString module_name(kMaxPathLength); MemoryMappedSegment segment(module_name.data(), kMaxPathLength); diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h index 543e27e39..208362d2f 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/lib/sanitizer_common/sanitizer_symbolizer.h @@ -119,6 +119,7 @@ class Symbolizer final { void AddHooks(StartSymbolizationHook start_hook, EndSymbolizationHook end_hook); + void RefreshModules(); const LoadedModule *FindModuleForAddress(uptr address); void InvalidateModuleList(); @@ -151,6 +152,7 @@ class Symbolizer final { uptr *module_offset, ModuleArch *module_arch); ListOfModules modules_; + ListOfModules fallback_modules_; // If stale, need to reload the modules before looking up addresses. bool modules_fresh_; diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc index caab4ca35..8f968e78a 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -163,29 +163,47 @@ bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, return true; } +void Symbolizer::RefreshModules() { + modules_.init(); + fallback_modules_.fallbackInit(); + RAW_CHECK(modules_.size() > 0); + modules_fresh_ = true; +} + +static const LoadedModule *SearchForModule(const ListOfModules &modules, + uptr address) { + for (uptr i = 0; i < modules.size(); i++) { + if (modules[i].containsAddress(address)) { + return &modules[i]; + } + } + return nullptr; +} + const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { bool modules_were_reloaded = false; if (!modules_fresh_) { - modules_.init(); - RAW_CHECK(modules_.size() > 0); - modules_fresh_ = true; + RefreshModules(); modules_were_reloaded = true; } - for (uptr i = 0; i < modules_.size(); i++) { - if (modules_[i].containsAddress(address)) { - return &modules_[i]; - } - } - // dlopen/dlclose interceptors invalidate the module list, but when - // interception is disabled, we need to retry if the lookup fails in - // case the module list changed. + const LoadedModule *module = SearchForModule(modules_, address); + if (module) return module; + + // dlopen/dlclose interceptors invalidate the module list, but when + // interception is disabled, we need to retry if the lookup fails in + // case the module list changed. #if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE if (!modules_were_reloaded) { - modules_fresh_ = false; - return FindModuleForAddress(address); + RefreshModules(); + module = SearchForModule(modules_, address); + if (module) return module; } #endif - return 0; + + if (fallback_modules_.size()) { + module = SearchForModule(fallback_modules_, address); + } + return module; } // For now we assume the following protocol: diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index a144db28c..f1a74d3f2 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -524,7 +524,7 @@ static uptr GetPreferredBase(const char *modname) { } void ListOfModules::init() { - clear(); + clearOrInit(); HANDLE cur_process = GetCurrentProcess(); // Query the list of modules. Start by assuming there are no more than 256 @@ -583,7 +583,9 @@ void ListOfModules::init() { modules_.push_back(cur_module); } UnmapOrDie(hmodules, modules_buffer_size); -}; +} + +void ListOfModules::fallbackInit() { clear(); } // We can't use atexit() directly at __asan_init time as the CRT is not fully // initialized at this point. Place the functions into a vector and use |