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