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(a: &end, mo: memory_order_acquire)); |
68 | } |
69 | |
70 | void OnLoad(uptr b, uptr e) { |
71 | begin = b; |
72 | atomic_store(a: &end, v: e, mo: memory_order_release); |
73 | } |
74 | |
75 | void OnUnload() { atomic_store(a: &end, v: 0, mo: 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(a: &ignored_ranges_count_, mo: 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(a: &instrumented_ranges_count_, mo: 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 | |