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  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  Mutex 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
90inline 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
104inline 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