aboutsummaryrefslogtreecommitdiff
path: root/lib/libtsan/sanitizer_common/sanitizer_libignore.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libtsan/sanitizer_common/sanitizer_libignore.h')
-rw-r--r--lib/libtsan/sanitizer_common/sanitizer_libignore.h126
1 files changed, 126 insertions, 0 deletions
diff --git a/lib/libtsan/sanitizer_common/sanitizer_libignore.h b/lib/libtsan/sanitizer_common/sanitizer_libignore.h
new file mode 100644
index 0000000000..0e26ff44c8
--- /dev/null
+++ b/lib/libtsan/sanitizer_common/sanitizer_libignore.h
@@ -0,0 +1,126 @@
+//===-- sanitizer_libignore.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// LibIgnore allows to ignore all interceptors called from a particular set
+// of dynamic libraries. LibIgnore can be initialized with several templates
+// of names of libraries to be ignored. It finds code ranges for the libraries;
+// and checks whether the provided PC value belongs to the code ranges.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_LIBIGNORE_H
+#define SANITIZER_LIBIGNORE_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_common.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_mutex.h"
+
+namespace __sanitizer {
+
+class LibIgnore {
+ public:
+ explicit LibIgnore(LinkerInitialized);
+
+ // Must be called during initialization.
+ void AddIgnoredLibrary(const char *name_templ);
+ void IgnoreNoninstrumentedModules(bool enable) {
+ track_instrumented_libs_ = enable;
+ }
+
+ // Must be called after a new dynamic library is loaded.
+ void OnLibraryLoaded(const char *name);
+
+ // Must be called after a dynamic library is unloaded.
+ void OnLibraryUnloaded();
+
+ // Checks whether the provided PC belongs to one of the ignored libraries or
+ // the PC should be ignored because it belongs to an non-instrumented module
+ // (when ignore_noninstrumented_modules=1). Also returns true via
+ // "pc_in_ignored_lib" if the PC is in an ignored library, false otherwise.
+ bool IsIgnored(uptr pc, bool *pc_in_ignored_lib) const;
+
+ // Checks whether the provided PC belongs to an instrumented module.
+ bool IsPcInstrumented(uptr pc) const;
+
+ private:
+ static const uptr kMaxIgnoredRanges = 128;
+ static const uptr kMaxInstrumentedRanges = 1024;
+ static const uptr kMaxLibs = 1024;
+ static const uptr kInvalidCodeRangeId = -1;
+
+ struct Lib {
+ char *templ;
+ char *name;
+ char *real_name; // target of symlink
+ uptr range_id;
+ bool loaded() const { return range_id != kInvalidCodeRangeId; };
+ };
+
+ struct LibCodeRange {
+ bool IsInRange(uptr pc) const {
+ return (pc >= begin && pc < atomic_load(&end, memory_order_acquire));
+ }
+
+ void OnLoad(uptr b, uptr e) {
+ begin = b;
+ atomic_store(&end, e, memory_order_release);
+ }
+
+ void OnUnload() { atomic_store(&end, 0, memory_order_release); }
+
+ private:
+ uptr begin;
+ // A value of 0 means the associated module was unloaded.
+ atomic_uintptr_t end;
+ };
+
+ // Hot part:
+ atomic_uintptr_t ignored_ranges_count_;
+ LibCodeRange ignored_code_ranges_[kMaxIgnoredRanges];
+
+ atomic_uintptr_t instrumented_ranges_count_;
+ LibCodeRange instrumented_code_ranges_[kMaxInstrumentedRanges];
+
+ // Cold part:
+ Mutex mutex_;
+ uptr count_;
+ Lib libs_[kMaxLibs];
+ bool track_instrumented_libs_;
+
+ // Disallow copying of LibIgnore objects.
+ LibIgnore(const LibIgnore&); // not implemented
+ void operator = (const LibIgnore&); // not implemented
+};
+
+inline bool LibIgnore::IsIgnored(uptr pc, bool *pc_in_ignored_lib) const {
+ const uptr n = atomic_load(&ignored_ranges_count_, memory_order_acquire);
+ for (uptr i = 0; i < n; i++) {
+ if (ignored_code_ranges_[i].IsInRange(pc)) {
+ *pc_in_ignored_lib = true;
+ return true;
+ }
+ }
+ *pc_in_ignored_lib = false;
+ if (track_instrumented_libs_ && !IsPcInstrumented(pc))
+ return true;
+ return false;
+}
+
+inline bool LibIgnore::IsPcInstrumented(uptr pc) const {
+ const uptr n = atomic_load(&instrumented_ranges_count_, memory_order_acquire);
+ for (uptr i = 0; i < n; i++) {
+ if (instrumented_code_ranges_[i].IsInRange(pc))
+ return true;
+ }
+ return false;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_LIBIGNORE_H