1353944Sdim//===-- sanitizer_libignore.cpp -------------------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim
9353944Sdim#include "sanitizer_platform.h"
10353944Sdim
11353944Sdim#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \
12353944Sdim    SANITIZER_NETBSD || SANITIZER_OPENBSD
13353944Sdim
14353944Sdim#include "sanitizer_libignore.h"
15353944Sdim#include "sanitizer_flags.h"
16353944Sdim#include "sanitizer_posix.h"
17353944Sdim#include "sanitizer_procmaps.h"
18353944Sdim
19353944Sdimnamespace __sanitizer {
20353944Sdim
21353944SdimLibIgnore::LibIgnore(LinkerInitialized) {
22353944Sdim}
23353944Sdim
24353944Sdimvoid LibIgnore::AddIgnoredLibrary(const char *name_templ) {
25353944Sdim  BlockingMutexLock lock(&mutex_);
26353944Sdim  if (count_ >= kMaxLibs) {
27353944Sdim    Report("%s: too many ignored libraries (max: %d)\n", SanitizerToolName,
28353944Sdim           kMaxLibs);
29353944Sdim    Die();
30353944Sdim  }
31353944Sdim  Lib *lib = &libs_[count_++];
32353944Sdim  lib->templ = internal_strdup(name_templ);
33353944Sdim  lib->name = nullptr;
34353944Sdim  lib->real_name = nullptr;
35353944Sdim  lib->loaded = false;
36353944Sdim}
37353944Sdim
38353944Sdimvoid LibIgnore::OnLibraryLoaded(const char *name) {
39353944Sdim  BlockingMutexLock lock(&mutex_);
40353944Sdim  // Try to match suppressions with symlink target.
41353944Sdim  InternalScopedString buf(kMaxPathLength);
42353944Sdim  if (name && internal_readlink(name, buf.data(), buf.size() - 1) > 0 &&
43353944Sdim      buf[0]) {
44353944Sdim    for (uptr i = 0; i < count_; i++) {
45353944Sdim      Lib *lib = &libs_[i];
46353944Sdim      if (!lib->loaded && (!lib->real_name) &&
47353944Sdim          TemplateMatch(lib->templ, name))
48353944Sdim        lib->real_name = internal_strdup(buf.data());
49353944Sdim    }
50353944Sdim  }
51353944Sdim
52353944Sdim  // Scan suppressions list and find newly loaded and unloaded libraries.
53353944Sdim  ListOfModules modules;
54353944Sdim  modules.init();
55353944Sdim  for (uptr i = 0; i < count_; i++) {
56353944Sdim    Lib *lib = &libs_[i];
57353944Sdim    bool loaded = false;
58353944Sdim    for (const auto &mod : modules) {
59353944Sdim      for (const auto &range : mod.ranges()) {
60353944Sdim        if (!range.executable)
61353944Sdim          continue;
62353944Sdim        if (!TemplateMatch(lib->templ, mod.full_name()) &&
63353944Sdim            !(lib->real_name &&
64353944Sdim            internal_strcmp(lib->real_name, mod.full_name()) == 0))
65353944Sdim          continue;
66353944Sdim        if (loaded) {
67353944Sdim          Report("%s: called_from_lib suppression '%s' is matched against"
68353944Sdim                 " 2 libraries: '%s' and '%s'\n",
69353944Sdim                 SanitizerToolName, lib->templ, lib->name, mod.full_name());
70353944Sdim          Die();
71353944Sdim        }
72353944Sdim        loaded = true;
73353944Sdim        if (lib->loaded)
74353944Sdim          continue;
75353944Sdim        VReport(1,
76353944Sdim                "Matched called_from_lib suppression '%s' against library"
77353944Sdim                " '%s'\n",
78353944Sdim                lib->templ, mod.full_name());
79353944Sdim        lib->loaded = true;
80353944Sdim        lib->name = internal_strdup(mod.full_name());
81353944Sdim        const uptr idx =
82353944Sdim            atomic_load(&ignored_ranges_count_, memory_order_relaxed);
83353944Sdim        CHECK_LT(idx, ARRAY_SIZE(ignored_code_ranges_));
84353944Sdim        ignored_code_ranges_[idx].begin = range.beg;
85353944Sdim        ignored_code_ranges_[idx].end = range.end;
86353944Sdim        atomic_store(&ignored_ranges_count_, idx + 1, memory_order_release);
87353944Sdim        break;
88353944Sdim      }
89353944Sdim    }
90353944Sdim    if (lib->loaded && !loaded) {
91353944Sdim      Report("%s: library '%s' that was matched against called_from_lib"
92353944Sdim             " suppression '%s' is unloaded\n",
93353944Sdim             SanitizerToolName, lib->name, lib->templ);
94353944Sdim      Die();
95353944Sdim    }
96353944Sdim  }
97353944Sdim
98353944Sdim  // Track instrumented ranges.
99353944Sdim  if (track_instrumented_libs_) {
100353944Sdim    for (const auto &mod : modules) {
101353944Sdim      if (!mod.instrumented())
102353944Sdim        continue;
103353944Sdim      for (const auto &range : mod.ranges()) {
104353944Sdim        if (!range.executable)
105353944Sdim          continue;
106353944Sdim        if (IsPcInstrumented(range.beg) && IsPcInstrumented(range.end - 1))
107353944Sdim          continue;
108353944Sdim        VReport(1, "Adding instrumented range %p-%p from library '%s'\n",
109353944Sdim                range.beg, range.end, mod.full_name());
110353944Sdim        const uptr idx =
111353944Sdim            atomic_load(&instrumented_ranges_count_, memory_order_relaxed);
112353944Sdim        CHECK_LT(idx, ARRAY_SIZE(instrumented_code_ranges_));
113353944Sdim        instrumented_code_ranges_[idx].begin = range.beg;
114353944Sdim        instrumented_code_ranges_[idx].end = range.end;
115353944Sdim        atomic_store(&instrumented_ranges_count_, idx + 1,
116353944Sdim                     memory_order_release);
117353944Sdim      }
118353944Sdim    }
119353944Sdim  }
120353944Sdim}
121353944Sdim
122353944Sdimvoid LibIgnore::OnLibraryUnloaded() {
123353944Sdim  OnLibraryLoaded(nullptr);
124353944Sdim}
125353944Sdim
126353944Sdim} // namespace __sanitizer
127353944Sdim
128353944Sdim#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC ||
129353944Sdim        // SANITIZER_NETBSD
130