master
  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
 19namespace __sanitizer {
 20
 21LibIgnore::LibIgnore(LinkerInitialized) {
 22}
 23
 24void LibIgnore::AddIgnoredLibrary(const char *name_templ) {
 25  Lock lock(&mutex_);
 26  if (count_ >= kMaxLibs) {
 27    Report("%s: too many ignored libraries (max: %zu)\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->range_id = kInvalidCodeRangeId;
 36}
 37
 38void 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(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->name = internal_strdup(mod.full_name());
 80        const uptr idx =
 81            atomic_load(&ignored_ranges_count_, memory_order_relaxed);
 82        CHECK_LT(idx, ARRAY_SIZE(ignored_code_ranges_));
 83        ignored_code_ranges_[idx].OnLoad(range.beg, range.end);
 84        // Record the index of the ignored range.
 85        lib->range_id = idx;
 86        atomic_store(&ignored_ranges_count_, idx + 1, memory_order_release);
 87        break;
 88      }
 89    }
 90    if (lib->loaded() && !loaded) {
 91      VReport(1,
 92              "%s: library '%s' that was matched against called_from_lib"
 93              " suppression '%s' is unloaded\n",
 94              SanitizerToolName, lib->name, lib->templ);
 95      // The library is unloaded so mark the ignored code range as unloaded.
 96      ignored_code_ranges_[lib->range_id].OnUnload();
 97      lib->range_id = kInvalidCodeRangeId;
 98    }
 99  }
100
101  // Track instrumented ranges.
102  if (track_instrumented_libs_) {
103    for (const auto &mod : modules) {
104      if (!mod.instrumented())
105        continue;
106      for (const auto &range : mod.ranges()) {
107        if (!range.executable)
108          continue;
109        if (IsPcInstrumented(range.beg) && IsPcInstrumented(range.end - 1))
110          continue;
111        VReport(1, "Adding instrumented range %p-%p from library '%s'\n",
112                (void *)range.beg, (void *)range.end, mod.full_name());
113        const uptr idx =
114            atomic_load(&instrumented_ranges_count_, memory_order_relaxed);
115        CHECK_LT(idx, ARRAY_SIZE(instrumented_code_ranges_));
116        instrumented_code_ranges_[idx].OnLoad(range.beg, range.end);
117        atomic_store(&instrumented_ranges_count_, idx + 1,
118                     memory_order_release);
119      }
120    }
121  }
122}
123
124void LibIgnore::OnLibraryUnloaded() {
125  OnLibraryLoaded(nullptr);
126}
127
128} // namespace __sanitizer
129
130#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_APPLE ||
131        // SANITIZER_NETBSD