1 //===-- sanitizer_libignore.h -----------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // LibIgnore allows to ignore all interceptors called from a particular set 10 // of dynamic libraries. LibIgnore can be initialized with several templates 11 // of names of libraries to be ignored. It finds code ranges for the libraries; 12 // and checks whether the provided PC value belongs to the code ranges. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #ifndef SANITIZER_LIBIGNORE_H 17 #define SANITIZER_LIBIGNORE_H 18 19 #include "sanitizer_internal_defs.h" 20 #include "sanitizer_common.h" 21 #include "sanitizer_atomic.h" 22 #include "sanitizer_mutex.h" 23 24 namespace __sanitizer { 25 26 class LibIgnore { 27 public: 28 explicit LibIgnore(LinkerInitialized); 29 30 // Must be called during initialization. 31 void AddIgnoredLibrary(const char *name_templ); 32 void IgnoreNoninstrumentedModules(bool enable) { 33 track_instrumented_libs_ = enable; 34 } 35 36 // Must be called after a new dynamic library is loaded. 37 void OnLibraryLoaded(const char *name); 38 39 // Must be called after a dynamic library is unloaded. 40 void OnLibraryUnloaded(); 41 42 // Checks whether the provided PC belongs to one of the ignored libraries or 43 // the PC should be ignored because it belongs to an non-instrumented module 44 // (when ignore_noninstrumented_modules=1). Also returns true via 45 // "pc_in_ignored_lib" if the PC is in an ignored library, false otherwise. 46 bool IsIgnored(uptr pc, bool *pc_in_ignored_lib) const; 47 48 // Checks whether the provided PC belongs to an instrumented module. 49 bool IsPcInstrumented(uptr pc) const; 50 51 private: 52 struct Lib { 53 char *templ; 54 char *name; 55 char *real_name; // target of symlink 56 bool loaded; 57 }; 58 59 struct LibCodeRange { 60 uptr begin; 61 uptr end; 62 }; 63 64 inline bool IsInRange(uptr pc, const LibCodeRange &range) const { 65 return (pc >= range.begin && pc < range.end); 66 } 67 68 static const uptr kMaxIgnoredRanges = 128; 69 static const uptr kMaxInstrumentedRanges = 1024; 70 static const uptr kMaxLibs = 1024; 71 72 // Hot part: 73 atomic_uintptr_t ignored_ranges_count_; 74 LibCodeRange ignored_code_ranges_[kMaxIgnoredRanges]; 75 76 atomic_uintptr_t instrumented_ranges_count_; 77 LibCodeRange instrumented_code_ranges_[kMaxInstrumentedRanges]; 78 79 // Cold part: 80 BlockingMutex mutex_; 81 uptr count_; 82 Lib libs_[kMaxLibs]; 83 bool track_instrumented_libs_; 84 85 // Disallow copying of LibIgnore objects. 86 LibIgnore(const LibIgnore&); // not implemented 87 void operator = (const LibIgnore&); // not implemented 88 }; 89 90 inline bool LibIgnore::IsIgnored(uptr pc, bool *pc_in_ignored_lib) const { 91 const uptr n = atomic_load(&ignored_ranges_count_, memory_order_acquire); 92 for (uptr i = 0; i < n; i++) { 93 if (IsInRange(pc, ignored_code_ranges_[i])) { 94 *pc_in_ignored_lib = true; 95 return true; 96 } 97 } 98 *pc_in_ignored_lib = false; 99 if (track_instrumented_libs_ && !IsPcInstrumented(pc)) 100 return true; 101 return false; 102 } 103 104 inline bool LibIgnore::IsPcInstrumented(uptr pc) const { 105 const uptr n = atomic_load(&instrumented_ranges_count_, memory_order_acquire); 106 for (uptr i = 0; i < n; i++) { 107 if (IsInRange(pc, instrumented_code_ranges_[i])) 108 return true; 109 } 110 return false; 111 } 112 113 } // namespace __sanitizer 114 115 #endif // SANITIZER_LIBIGNORE_H 116