master
  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
 24namespace __sanitizer {
 25
 26class 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  static const uptr kMaxIgnoredRanges = 128;
 53  static const uptr kMaxInstrumentedRanges = 1024;
 54  static const uptr kMaxLibs = 1024;
 55  static const uptr kInvalidCodeRangeId = -1;
 56
 57  struct Lib {
 58    char *templ;
 59    char *name;
 60    char *real_name;  // target of symlink
 61    uptr range_id;
 62    bool loaded() const { return range_id != kInvalidCodeRangeId; };
 63  };
 64
 65  struct LibCodeRange {
 66    bool IsInRange(uptr pc) const {
 67      return (pc >= begin && pc < atomic_load(&end, memory_order_acquire));
 68    }
 69
 70    void OnLoad(uptr b, uptr e) {
 71      begin = b;
 72      atomic_store(&end, e, memory_order_release);
 73    }
 74
 75    void OnUnload() { atomic_store(&end, 0, memory_order_release); }
 76
 77   private:
 78    uptr begin;
 79    // A value of 0 means the associated module was unloaded.
 80    atomic_uintptr_t end;
 81  };
 82
 83  // Hot part:
 84  atomic_uintptr_t ignored_ranges_count_;
 85  LibCodeRange ignored_code_ranges_[kMaxIgnoredRanges];
 86
 87  atomic_uintptr_t instrumented_ranges_count_;
 88  LibCodeRange instrumented_code_ranges_[kMaxInstrumentedRanges];
 89
 90  // Cold part:
 91  Mutex mutex_;
 92  uptr count_;
 93  Lib libs_[kMaxLibs];
 94  bool track_instrumented_libs_;
 95
 96  // Disallow copying of LibIgnore objects.
 97  LibIgnore(const LibIgnore&);  // not implemented
 98  void operator = (const LibIgnore&);  // not implemented
 99};
100
101inline bool LibIgnore::IsIgnored(uptr pc, bool *pc_in_ignored_lib) const {
102  const uptr n = atomic_load(&ignored_ranges_count_, memory_order_acquire);
103  for (uptr i = 0; i < n; i++) {
104    if (ignored_code_ranges_[i].IsInRange(pc)) {
105      *pc_in_ignored_lib = true;
106      return true;
107    }
108  }
109  *pc_in_ignored_lib = false;
110  if (track_instrumented_libs_ && !IsPcInstrumented(pc))
111    return true;
112  return false;
113}
114
115inline bool LibIgnore::IsPcInstrumented(uptr pc) const {
116  const uptr n = atomic_load(&instrumented_ranges_count_, memory_order_acquire);
117  for (uptr i = 0; i < n; i++) {
118    if (instrumented_code_ranges_[i].IsInRange(pc))
119      return true;
120  }
121  return false;
122}
123
124}  // namespace __sanitizer
125
126#endif  // SANITIZER_LIBIGNORE_H