xref: /llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_libignore.h (revision 79c4ece75f5fcc8a9e6bcd560f3184cfab04378a)
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   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 
101 inline 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 
115 inline 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
127