1 | //===-- sanitizer_libignore.cpp -------------------------------------------===// |
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 | #include "sanitizer_platform.h" |
10 | |
11 | #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_APPLE || \ |
12 | SANITIZER_NETBSD |
13 | |
14 | #include "sanitizer_libignore.h" |
15 | #include "sanitizer_flags.h" |
16 | #include "sanitizer_posix.h" |
17 | #include "sanitizer_procmaps.h" |
18 | |
19 | namespace __sanitizer { |
20 | |
21 | LibIgnore::LibIgnore(LinkerInitialized) { |
22 | } |
23 | |
24 | void LibIgnore::AddIgnoredLibrary(const char *name_templ) { |
25 | Lock lock(&mutex_); |
26 | if (count_ >= kMaxLibs) { |
27 | Report(format: "%s: too many ignored libraries (max: %zu)\n" , SanitizerToolName, |
28 | kMaxLibs); |
29 | Die(); |
30 | } |
31 | Lib *lib = &libs_[count_++]; |
32 | lib->templ = internal_strdup(s: name_templ); |
33 | lib->name = nullptr; |
34 | lib->real_name = nullptr; |
35 | lib->loaded = false; |
36 | } |
37 | |
38 | void LibIgnore::OnLibraryLoaded(const char *name) { |
39 | Lock lock(&mutex_); |
40 | // Try to match suppressions with symlink target. |
41 | InternalMmapVector<char> buf(kMaxPathLength); |
42 | if (name && internal_readlink(path: name, buf: buf.data(), bufsize: buf.size() - 1) > 0 && |
43 | buf[0]) { |
44 | for (uptr i = 0; i < count_; i++) { |
45 | Lib *lib = &libs_[i]; |
46 | if (!lib->loaded && (!lib->real_name) && |
47 | TemplateMatch(templ: lib->templ, str: name)) |
48 | lib->real_name = internal_strdup(s: buf.data()); |
49 | } |
50 | } |
51 | |
52 | // Scan suppressions list and find newly loaded and unloaded libraries. |
53 | ListOfModules modules; |
54 | modules.init(); |
55 | for (uptr i = 0; i < count_; i++) { |
56 | Lib *lib = &libs_[i]; |
57 | bool loaded = false; |
58 | for (const auto &mod : modules) { |
59 | for (const auto &range : mod.ranges()) { |
60 | if (!range.executable) |
61 | continue; |
62 | if (!TemplateMatch(templ: lib->templ, str: mod.full_name()) && |
63 | !(lib->real_name && |
64 | internal_strcmp(s1: lib->real_name, s2: mod.full_name()) == 0)) |
65 | continue; |
66 | if (loaded) { |
67 | Report(format: "%s: called_from_lib suppression '%s' is matched against" |
68 | " 2 libraries: '%s' and '%s'\n" , |
69 | SanitizerToolName, lib->templ, lib->name, mod.full_name()); |
70 | Die(); |
71 | } |
72 | loaded = true; |
73 | if (lib->loaded) |
74 | continue; |
75 | VReport(1, |
76 | "Matched called_from_lib suppression '%s' against library" |
77 | " '%s'\n" , |
78 | lib->templ, mod.full_name()); |
79 | lib->loaded = true; |
80 | lib->name = internal_strdup(s: mod.full_name()); |
81 | const uptr idx = |
82 | atomic_load(a: &ignored_ranges_count_, mo: memory_order_relaxed); |
83 | CHECK_LT(idx, ARRAY_SIZE(ignored_code_ranges_)); |
84 | ignored_code_ranges_[idx].begin = range.beg; |
85 | ignored_code_ranges_[idx].end = range.end; |
86 | atomic_store(a: &ignored_ranges_count_, v: idx + 1, mo: memory_order_release); |
87 | break; |
88 | } |
89 | } |
90 | if (lib->loaded && !loaded) { |
91 | Report(format: "%s: library '%s' that was matched against called_from_lib" |
92 | " suppression '%s' is unloaded\n" , |
93 | SanitizerToolName, lib->name, lib->templ); |
94 | Die(); |
95 | } |
96 | } |
97 | |
98 | // Track instrumented ranges. |
99 | if (track_instrumented_libs_) { |
100 | for (const auto &mod : modules) { |
101 | if (!mod.instrumented()) |
102 | continue; |
103 | for (const auto &range : mod.ranges()) { |
104 | if (!range.executable) |
105 | continue; |
106 | if (IsPcInstrumented(pc: range.beg) && IsPcInstrumented(pc: range.end - 1)) |
107 | continue; |
108 | VReport(1, "Adding instrumented range 0x%zx-0x%zx from library '%s'\n" , |
109 | range.beg, range.end, mod.full_name()); |
110 | const uptr idx = |
111 | atomic_load(a: &instrumented_ranges_count_, mo: memory_order_relaxed); |
112 | CHECK_LT(idx, ARRAY_SIZE(instrumented_code_ranges_)); |
113 | instrumented_code_ranges_[idx].begin = range.beg; |
114 | instrumented_code_ranges_[idx].end = range.end; |
115 | atomic_store(a: &instrumented_ranges_count_, v: idx + 1, |
116 | mo: memory_order_release); |
117 | } |
118 | } |
119 | } |
120 | } |
121 | |
122 | void LibIgnore::OnLibraryUnloaded() { |
123 | OnLibraryLoaded(name: nullptr); |
124 | } |
125 | |
126 | } // namespace __sanitizer |
127 | |
128 | #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_APPLE || |
129 | // SANITIZER_NETBSD |
130 | |