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);
IgnoreNoninstrumentedModules(bool enable)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 
IsInRange(uptr pc,const LibCodeRange & range)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   BlockingMutex 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 
IsIgnored(uptr pc,bool * pc_in_ignored_lib)90 inline 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 
IsPcInstrumented(uptr pc)104 inline 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