forked from OSchip/llvm-project
				
			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 llvm-svn: 314431
This commit is contained in:
		
							parent
							
								
									fd6b8a67fb
								
							
						
					
					
						commit
						b9a32d470a
					
				| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,22 +463,38 @@ 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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
// Still, this is better than nothing if /proc/self/statm is not available
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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_;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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];
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue