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_MAC || \ 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 BlockingMutexLock lock(&mutex_); 26 if (count_ >= kMaxLibs) { 27 Report("%s: too many ignored libraries (max: %d)\n", SanitizerToolName, 28 kMaxLibs); 29 Die(); 30 } 31 Lib *lib = &libs_[count_++]; 32 lib->templ = internal_strdup(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 BlockingMutexLock lock(&mutex_); 40 // Try to match suppressions with symlink target. 41 InternalMmapVector<char> buf(kMaxPathLength); 42 if (name && internal_readlink(name, buf.data(), 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(lib->templ, name)) 48 lib->real_name = internal_strdup(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(lib->templ, mod.full_name()) && 63 !(lib->real_name && 64 internal_strcmp(lib->real_name, mod.full_name()) == 0)) 65 continue; 66 if (loaded) { 67 Report("%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(mod.full_name()); 81 const uptr idx = 82 atomic_load(&ignored_ranges_count_, 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(&ignored_ranges_count_, idx + 1, memory_order_release); 87 break; 88 } 89 } 90 if (lib->loaded && !loaded) { 91 Report("%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(range.beg) && IsPcInstrumented(range.end - 1)) 107 continue; 108 VReport(1, "Adding instrumented range %p-%p from library '%s'\n", 109 range.beg, range.end, mod.full_name()); 110 const uptr idx = 111 atomic_load(&instrumented_ranges_count_, 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(&instrumented_ranges_count_, idx + 1, 116 memory_order_release); 117 } 118 } 119 } 120 } 121 122 void LibIgnore::OnLibraryUnloaded() { 123 OnLibraryLoaded(nullptr); 124 } 125 126 } // namespace __sanitizer 127 128 #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || 129 // SANITIZER_NETBSD 130