diff options
Diffstat (limited to 'lib/libtsan/sanitizer_common/sanitizer_libignore.h')
| -rw-r--r-- | lib/libtsan/sanitizer_common/sanitizer_libignore.h | 126 |
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 |
