Index: clang/include/clang/Basic/Features.def =================================================================== --- clang/include/clang/Basic/Features.def +++ clang/include/clang/Basic/Features.def @@ -86,8 +86,6 @@ SanitizerKind::KernelMemory)) FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread)) FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow)) -FEATURE(efficiency_sanitizer, - LangOpts.Sanitize.hasOneOf(SanitizerKind::Efficiency)) FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo)) // Objective-C features FEATURE(objc_arr, LangOpts.ObjCAutoRefCount) // FIXME: REMOVE? Index: clang/include/clang/Basic/Sanitizers.def =================================================================== --- clang/include/clang/Basic/Sanitizers.def +++ clang/include/clang/Basic/Sanitizers.def @@ -165,13 +165,6 @@ SANITIZER("local-bounds", LocalBounds) SANITIZER_GROUP("bounds", Bounds, ArrayBounds | LocalBounds) -// EfficiencySanitizer -SANITIZER("efficiency-cache-frag", EfficiencyCacheFrag) -SANITIZER("efficiency-working-set", EfficiencyWorkingSet) -// Meta-group only used internally. -SANITIZER_GROUP("efficiency-all", Efficiency, - EfficiencyCacheFrag | EfficiencyWorkingSet) - // Scudo hardened allocator SANITIZER("scudo", Scudo) Index: clang/include/clang/Driver/SanitizerArgs.h =================================================================== --- clang/include/clang/Driver/SanitizerArgs.h +++ clang/include/clang/Driver/SanitizerArgs.h @@ -73,9 +73,6 @@ bool needsCfiRt() const; bool needsCfiDiagRt() const; bool needsStatsRt() const { return Stats; } - bool needsEsanRt() const { - return Sanitizers.hasOneOf(SanitizerKind::Efficiency); - } bool needsScudoRt() const { return Sanitizers.has(SanitizerKind::Scudo); } bool requiresPIE() const; Index: clang/lib/CodeGen/BackendUtil.cpp =================================================================== --- clang/lib/CodeGen/BackendUtil.cpp +++ clang/lib/CodeGen/BackendUtil.cpp @@ -319,19 +319,6 @@ PM.add(createDataFlowSanitizerPass(LangOpts.SanitizerBlacklistFiles)); } -static void addEfficiencySanitizerPass(const PassManagerBuilder &Builder, - legacy::PassManagerBase &PM) { - const PassManagerBuilderWrapper &BuilderWrapper = - static_cast(Builder); - const LangOptions &LangOpts = BuilderWrapper.getLangOpts(); - EfficiencySanitizerOptions Opts; - if (LangOpts.Sanitize.has(SanitizerKind::EfficiencyCacheFrag)) - Opts.ToolType = EfficiencySanitizerOptions::ESAN_CacheFrag; - else if (LangOpts.Sanitize.has(SanitizerKind::EfficiencyWorkingSet)) - Opts.ToolType = EfficiencySanitizerOptions::ESAN_WorkingSet; - PM.add(createEfficiencySanitizerPass(Opts)); -} - static TargetLibraryInfoImpl *createTLII(llvm::Triple &TargetTriple, const CodeGenOptions &CodeGenOpts) { TargetLibraryInfoImpl *TLII = new TargetLibraryInfoImpl(TargetTriple); @@ -656,13 +643,6 @@ addDataFlowSanitizerPass); } - if (LangOpts.Sanitize.hasOneOf(SanitizerKind::Efficiency)) { - PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast, - addEfficiencySanitizerPass); - PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, - addEfficiencySanitizerPass); - } - // Set up the per-function pass manager. FPM.add(new TargetLibraryInfoWrapperPass(*TLII)); if (CodeGenOpts.VerifyModule) Index: clang/lib/Driver/SanitizerArgs.cpp =================================================================== --- clang/lib/Driver/SanitizerArgs.cpp +++ clang/lib/Driver/SanitizerArgs.cpp @@ -401,31 +401,24 @@ std::make_pair(SanitizerKind::HWAddress, SanitizerKind::Address | SanitizerKind::Thread | SanitizerKind::Memory | SanitizerKind::KernelAddress), - std::make_pair(SanitizerKind::Efficiency, - SanitizerKind::Address | SanitizerKind::HWAddress | - SanitizerKind::Leak | SanitizerKind::Thread | - SanitizerKind::Memory | SanitizerKind::KernelAddress), std::make_pair(SanitizerKind::Scudo, SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Leak | SanitizerKind::Thread | - SanitizerKind::Memory | SanitizerKind::KernelAddress | - SanitizerKind::Efficiency), + SanitizerKind::Memory | SanitizerKind::KernelAddress), std::make_pair(SanitizerKind::SafeStack, SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Leak | SanitizerKind::Thread | - SanitizerKind::Memory | SanitizerKind::KernelAddress | - SanitizerKind::Efficiency), + SanitizerKind::Memory | SanitizerKind::KernelAddress), std::make_pair(SanitizerKind::KernelHWAddress, SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Leak | SanitizerKind::Thread | SanitizerKind::Memory | SanitizerKind::KernelAddress | - SanitizerKind::Efficiency | SanitizerKind::SafeStack), + SanitizerKind::SafeStack), std::make_pair(SanitizerKind::KernelMemory, SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Leak | SanitizerKind::Thread | SanitizerKind::Memory | SanitizerKind::KernelAddress | - SanitizerKind::Efficiency | SanitizerKind::Scudo | - SanitizerKind::SafeStack)}; + SanitizerKind::Scudo | SanitizerKind::SafeStack)}; // Enable toolchain specific default sanitizers if not explicitly disabled. SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove; @@ -1011,10 +1004,6 @@ if (A->getOption().matches(options::OPT_fsanitize_EQ) && 0 == strcmp("all", Value)) Kind = SanitizerMask(); - // Similarly, don't accept -fsanitize=efficiency-all. - else if (A->getOption().matches(options::OPT_fsanitize_EQ) && - 0 == strcmp("efficiency-all", Value)) - Kind = SanitizerMask(); else Kind = parseSanitizerValue(Value, /*AllowGroups=*/true); Index: clang/lib/Driver/ToolChains/CommonArgs.cpp =================================================================== --- clang/lib/Driver/ToolChains/CommonArgs.cpp +++ clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -713,8 +713,6 @@ NonWholeStaticRuntimes.push_back("stats"); RequiredSymbols.push_back("__sanitizer_stats_register"); } - if (SanArgs.needsEsanRt()) - StaticRuntimes.push_back("esan"); if (SanArgs.needsScudoRt()) { if (SanArgs.requiresMinimalRuntime()) { StaticRuntimes.push_back("scudo_minimal"); Index: clang/lib/Driver/ToolChains/Darwin.cpp =================================================================== --- clang/lib/Driver/ToolChains/Darwin.cpp +++ clang/lib/Driver/ToolChains/Darwin.cpp @@ -1115,8 +1115,6 @@ AddLinkRuntimeLib(Args, CmdArgs, "stats_client", RLO_AlwaysLink); AddLinkSanitizerLibArgs(Args, CmdArgs, "stats"); } - if (Sanitize.needsEsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "esan"); const XRayArgs &XRay = getXRayArgs(); if (XRay.needsXRayRt()) { Index: clang/lib/Driver/ToolChains/Linux.cpp =================================================================== --- clang/lib/Driver/ToolChains/Linux.cpp +++ clang/lib/Driver/ToolChains/Linux.cpp @@ -1005,8 +1005,6 @@ Res |= SanitizerKind::Thread; if (IsX86_64) Res |= SanitizerKind::KernelMemory; - if (IsX86_64 || IsMIPS64) - Res |= SanitizerKind::Efficiency; if (IsX86 || IsX86_64) Res |= SanitizerKind::Function; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch || Index: clang/lib/Driver/ToolChains/NetBSD.cpp =================================================================== --- clang/lib/Driver/ToolChains/NetBSD.cpp +++ clang/lib/Driver/ToolChains/NetBSD.cpp @@ -471,7 +471,6 @@ } if (IsX86_64) { Res |= SanitizerKind::DataFlow; - Res |= SanitizerKind::Efficiency; Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; Res |= SanitizerKind::HWAddress; Index: clang/test/Driver/esan.c =================================================================== --- clang/test/Driver/esan.c +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %clang -target x86_64-unknown-linux -fsanitize=efficiency-cache-frag %s -S -emit-llvm -o - | FileCheck %s -// RUN: %clang -O1 -target x86_64-unknown-linux -fsanitize=efficiency-cache-frag %s -S -emit-llvm -o - | FileCheck %s -// RUN: %clang -O2 -target x86_64-unknown-linux -fsanitize=efficiency-cache-frag %s -S -emit-llvm -o - | FileCheck %s -// RUN: %clang -O3 -target x86_64-unknown-linux -fsanitize=efficiency-cache-frag %s -S -emit-llvm -o - | FileCheck %s -// RUN: %clang -target x86_64-unknown-linux -fsanitize=efficiency-working-set %s -S -emit-llvm -o - | FileCheck %s -// RUN: %clang -O1 -target x86_64-unknown-linux -fsanitize=efficiency-working-set %s -S -emit-llvm -o - | FileCheck %s -// RUN: %clang -O2 -target x86_64-unknown-linux -fsanitize=efficiency-working-set %s -S -emit-llvm -o - | FileCheck %s -// RUN: %clang -O3 -target x86_64-unknown-linux -fsanitize=efficiency-working-set %s -S -emit-llvm -o - | FileCheck %s -// RUN: %clang -target mips64-unknown-linux -fsanitize=efficiency-cache-frag %s -S -emit-llvm -o - | FileCheck %s -// RUN: %clang -target mips64-unknown-linux -fsanitize=efficiency-working-set %s -S -emit-llvm -o - | FileCheck %s -// RUN: %clang -target mips64el-unknown-linux -fsanitize=efficiency-cache-frag %s -S -emit-llvm -o - | FileCheck %s -// RUN: %clang -target mips64el-unknown-linux -fsanitize=efficiency-working-set %s -S -emit-llvm -o - | FileCheck %s -// Verify that -fsanitize=efficiency-* invokes esan instrumentation. - -int foo(int *a) { return *a; } -// CHECK: __esan_init Index: clang/test/Driver/fsanitize.c =================================================================== --- clang/test/Driver/fsanitize.c +++ clang/test/Driver/fsanitize.c @@ -181,30 +181,6 @@ // RUN: %clang -target x86_64-linux-gnu -fsanitize=hwaddress,address -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANHA-SANA // CHECK-SANHA-SANA: '-fsanitize=hwaddress' not allowed with '-fsanitize=address' -// RUN: %clang -target x86_64-linux-gnu -fsanitize=efficiency-cache-frag,address -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANE-SANA -// RUN: %clang -target x86_64-linux-gnu -fsanitize=efficiency-working-set,address -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANE-SANA -// CHECK-SANE-SANA: '-fsanitize=efficiency-{{.*}}' not allowed with '-fsanitize=address' - -// RUN: %clang -target x86_64-linux-gnu -fsanitize=efficiency-cache-frag,leak -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANE-SANL -// RUN: %clang -target x86_64-linux-gnu -fsanitize=efficiency-working-set,leak -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANE-SANL -// CHECK-SANE-SANL: '-fsanitize=efficiency-{{.*}}' not allowed with '-fsanitize=leak' - -// RUN: %clang -target x86_64-linux-gnu -fsanitize=efficiency-cache-frag,thread -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANE-SANT -// RUN: %clang -target x86_64-linux-gnu -fsanitize=efficiency-working-set,thread -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANE-SANT -// CHECK-SANE-SANT: '-fsanitize=efficiency-{{.*}}' not allowed with '-fsanitize=thread' - -// RUN: %clang -target x86_64-linux-gnu -fsanitize=efficiency-cache-frag,memory -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANE-SANM -// RUN: %clang -target x86_64-linux-gnu -fsanitize=efficiency-working-set,memory -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANE-SANM -// CHECK-SANE-SANM: '-fsanitize=efficiency-{{.*}}' not allowed with '-fsanitize=memory' - -// RUN: %clang -target x86_64-linux-gnu -fsanitize=efficiency-cache-frag,kernel-memory -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANE-SANKM -// RUN: %clang -target x86_64-linux-gnu -fsanitize=efficiency-working-set,kernel-memory -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANE-SANKM -// CHECK-SANE-SANKM: '-fsanitize=kernel-memory' not allowed with '-fsanitize=efficiency-{{.*}}' - -// RUN: %clang -target x86_64-linux-gnu -fsanitize=efficiency-cache-frag,kernel-address -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANE-SANKA -// RUN: %clang -target x86_64-linux-gnu -fsanitize=efficiency-working-set,kernel-address -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANE-SANKA -// CHECK-SANE-SANKA: '-fsanitize=efficiency-{{.*}}' not allowed with '-fsanitize=kernel-address' - // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-use-after-scope %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-SCOPE // RUN: %clang_cl --target=x86_64-windows -fsanitize=address -fsanitize-address-use-after-scope -### -- %s 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-SCOPE // CHECK-USE-AFTER-SCOPE: -cc1{{.*}}-fsanitize-address-use-after-scope @@ -546,10 +522,6 @@ // RUN: %clang -target i386-pc-openbsd -fsanitize=memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MSAN-OPENBSD // CHECK-MSAN-OPENBSD: unsupported option '-fsanitize=memory' for target 'i386-pc-openbsd' -// RUN: %clang -target i386-pc-openbsd -fsanitize=efficiency-cache-frag %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-OPENBSD -// RUN: %clang -target i386-pc-openbsd -fsanitize=efficiency-working-set %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-OPENBSD -// CHECK-ESAN-OPENBSD: error: unsupported option '-fsanitize=efficiency-{{.*}}' for target 'i386-pc-openbsd' - // RUN: %clang -target x86_64-apple-darwin -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-LSAN-X86-64-DARWIN // CHECK-LSAN-X86-64-DARWIN-NOT: unsupported option @@ -571,31 +543,6 @@ // RUN: %clang -target i386-apple-tvossimulator -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-LSAN-I386-TVOSSIMULATOR // CHECK-LSAN-I386-TVOSSIMULATOR-NOT: unsupported option -// RUN: %clang -target i686-linux-gnu -fsanitize=efficiency-cache-frag %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-X86 -// RUN: %clang -target i686-linux-gnu -fsanitize=efficiency-working-set %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-X86 -// CHECK-ESAN-X86: error: unsupported option '-fsanitize=efficiency-{{.*}}' for target 'i686-unknown-linux-gnu' - -// RUN: %clang -target x86_64-apple-darwin10 -fsanitize=efficiency-cache-frag %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-DARWIN -// RUN: %clang -target x86_64-apple-darwin10 -fsanitize=efficiency-working-set %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-DARWIN -// CHECK-ESAN-DARWIN: unsupported option '-fsanitize=efficiency-{{.*}}' for target 'x86_64-apple-darwin10' - -// RUN: %clang -target i386-apple-darwin -fsanitize=efficiency-cache-frag %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-I386-DARWIN -// RUN: %clang -target i386-apple-darwin -fsanitize=efficiency-working-set %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-I386-DARWIN -// CHECK-ESAN-I386-DARWIN: unsupported option '-fsanitize=efficiency-{{.*}}' for target 'i386-apple-darwin' - -// RUN: %clang -target arm-apple-ios -fsanitize=efficiency-cache-frag %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-ARM-IOS -// RUN: %clang -target arm-apple-ios -fsanitize=efficiency-working-set %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-ARM-IOS -// CHECK-ESAN-ARM-IOS: unsupported option '-fsanitize=efficiency-{{.*}}' for target 'arm-apple-ios' - -// RUN: %clang -target i386-apple-iossimulator -fsanitize=efficiency-cache-frag %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-I386-IOSSIMULATOR -// RUN: %clang -target i386-apple-iossimulator -fsanitize=efficiency-working-set %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-I386-IOSSIMULATOR -// CHECK-ESAN-I386-IOSSIMULATOR: unsupported option '-fsanitize=efficiency-{{.*}}' for target 'i386-apple-iossimulator-simulator' - -// RUN: %clang -target i386-apple-tvossimulator -fsanitize=efficiency-cache-frag %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-I386-TVOSSIMULATOR -// RUN: %clang -target i386-apple-tvossimulator -fsanitize=efficiency-working-set %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-I386-TVOSSIMULATOR -// CHECK-ESAN-I386-TVOSSIMULATOR: unsupported option '-fsanitize=efficiency-{{.*}}' for target 'i386-apple-tvossimulator-simulator' - - // RUN: %clang -target x86_64-linux-gnu -fvisibility=hidden -fsanitize=cfi -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI // RUN: %clang -target x86_64-apple-darwin10 -fvisibility=hidden -fsanitize=cfi -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI @@ -783,9 +730,6 @@ // CHECK-MSAN-PS4: unsupported option '-fsanitize=memory' for target 'x86_64-scei-ps4' // RUN: %clang -target x86_64-scei-ps4 -fsanitize=thread %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TSAN-PS4 // CHECK-TSAN-PS4: unsupported option '-fsanitize=thread' for target 'x86_64-scei-ps4' -// RUN: %clang -target x86_64-scei-ps4 -fsanitize=efficiency-cache-frag %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-PS4 -// RUN: %clang -target x86_64-scei-ps4 -fsanitize=efficiency-working-set %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-PS4 -// CHECK-ESAN-PS4: unsupported option '-fsanitize=efficiency-{{.*}}' for target 'x86_64-scei-ps4' // RUN: %clang -target x86_64-scei-ps4 -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-PS4 // Make sure there are no *.{o,bc} or -l passed before the ASan library. // CHECK-ASAN-PS4-NOT: {{(\.(o|bc)"? |-l).*-lSceDbgAddressSanitizer_stub_weak}} Index: clang/test/Driver/sanitize_unwind_tables.c =================================================================== --- clang/test/Driver/sanitize_unwind_tables.c +++ clang/test/Driver/sanitize_unwind_tables.c @@ -7,8 +7,6 @@ // RUN: %clang -target x86_64-linux-gnu -fsanitize=memory %s -### 2>&1 | FileCheck %s // RUN: %clang -target x86_64-linux-gnu -fsanitize=thread %s -### 2>&1 | FileCheck %s // RUN: %clang -target x86_64-linux-gnu -fsanitize=dataflow %s -### 2>&1 | FileCheck %s -// RUN: %clang -target x86_64-linux-gnu -fsanitize=efficiency-cache-frag %s -### 2>&1 | FileCheck %s -// RUN: %clang -target x86_64-linux-gnu -fsanitize=efficiency-working-set %s -### 2>&1 | FileCheck %s // RUN: %clang -target aarch64-linux-gnu -fsanitize=hwaddress %s -### 2>&1 | FileCheck %s // RUN: %clang -target aarch64-linux-android -fsanitize=hwaddress %s -### 2>&1 | FileCheck %s Index: clang/test/Driver/sanitizer-ld.c =================================================================== --- clang/test/Driver/sanitizer-ld.c +++ clang/test/Driver/sanitizer-ld.c @@ -680,16 +680,6 @@ // RUN: | FileCheck --check-prefix=CHECK-NOLIB-PS4 %s // CHECK-NOLIB-PS4-NOT: SceDbgAddressSanitizer_stub_weak -// RUN: %clang -fsanitize=efficiency-cache-frag %s -### -o %t.o 2>&1 \ -// RUN: -target x86_64-unknown-linux -fuse-ld=ld \ -// RUN: | FileCheck --check-prefix=CHECK-ESAN-LINUX %s -// RUN: %clang -fsanitize=efficiency-working-set %s -### -o %t.o 2>&1 \ -// RUN: -target x86_64-unknown-linux -fuse-ld=ld \ -// RUN: | FileCheck --check-prefix=CHECK-ESAN-LINUX %s -// -// CHECK-ESAN-LINUX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}" -// CHECK-ESAN-LINUX: libclang_rt.esan-x86_64.a - // RUN: %clang -fsanitize=scudo %s -### -o %t.o 2>&1 \ // RUN: -target i386-unknown-linux -fuse-ld=ld \ // RUN: --sysroot=%S/Inputs/basic_linux_tree \ Index: clang/test/Lexer/has_feature_efficiency_sanitizer.cpp =================================================================== --- clang/test/Lexer/has_feature_efficiency_sanitizer.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// RUN: %clang_cc1 -E -fsanitize=efficiency-cache-frag %s -o - | FileCheck --check-prefix=CHECK-ESAN %s -// RUN: %clang_cc1 -E -fsanitize=efficiency-working-set %s -o - | FileCheck --check-prefix=CHECK-ESAN %s -// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-ESAN %s - -#if __has_feature(efficiency_sanitizer) -int EfficiencySanitizerEnabled(); -#else -int EfficiencySanitizerDisabled(); -#endif - -// CHECK-ESAN: EfficiencySanitizerEnabled -// CHECK-NO-ESAN: EfficiencySanitizerDisabled Index: compiler-rt/cmake/config-ix.cmake =================================================================== --- compiler-rt/cmake/config-ix.cmake +++ compiler-rt/cmake/config-ix.cmake @@ -246,7 +246,6 @@ ${MIPS32} ${MIPS64} ${PPC64} ${S390X}) set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64}) set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS64}) -set(ALL_ESAN_SUPPORTED_ARCH ${X86_64} ${MIPS64}) set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} ${PPC64}) set(ALL_SCUDO_STANDALONE_SUPPORTED_ARCH ${X86} ${X86_64}) if(APPLE) @@ -456,9 +455,6 @@ list_intersect(CFI_SUPPORTED_ARCH ALL_CFI_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH) - list_intersect(ESAN_SUPPORTED_ARCH - ALL_ESAN_SUPPORTED_ARCH - SANITIZER_COMMON_SUPPORTED_ARCH) list_intersect(SCUDO_SUPPORTED_ARCH ALL_SCUDO_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH) @@ -497,7 +493,6 @@ filter_available_targets(SAFESTACK_SUPPORTED_ARCH ${ALL_SAFESTACK_SUPPORTED_ARCH}) filter_available_targets(CFI_SUPPORTED_ARCH ${ALL_CFI_SUPPORTED_ARCH}) - filter_available_targets(ESAN_SUPPORTED_ARCH ${ALL_ESAN_SUPPORTED_ARCH}) filter_available_targets(SCUDO_SUPPORTED_ARCH ${ALL_SCUDO_SUPPORTED_ARCH}) filter_available_targets(SCUDO_STANDALONE_SUPPORTED_ARCH ${ALL_SCUDO_STANDALONE_SUPPORTED_ARCH}) filter_available_targets(XRAY_SUPPORTED_ARCH ${ALL_XRAY_SUPPORTED_ARCH}) @@ -530,7 +525,7 @@ set(OS_NAME "${CMAKE_SYSTEM_NAME}") endif() -set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;safestack;cfi;esan;scudo;ubsan_minimal) +set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo;ubsan_minimal) set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING "sanitizers to build if supported on the target (all;${ALL_SANITIZERS})") list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}") @@ -634,13 +629,6 @@ set(COMPILER_RT_HAS_CFI FALSE) endif() -if (COMPILER_RT_HAS_SANITIZER_COMMON AND ESAN_SUPPORTED_ARCH AND - OS_NAME MATCHES "Linux|FreeBSD") - set(COMPILER_RT_HAS_ESAN TRUE) -else() - set(COMPILER_RT_HAS_ESAN FALSE) -endif() - #TODO(kostyak): add back Android & Fuchsia when the code settles a bit. if (SCUDO_STANDALONE_SUPPORTED_ARCH AND OS_NAME MATCHES "Linux") set(COMPILER_RT_HAS_SCUDO_STANDALONE TRUE) Index: compiler-rt/include/CMakeLists.txt =================================================================== --- compiler-rt/include/CMakeLists.txt +++ compiler-rt/include/CMakeLists.txt @@ -5,7 +5,6 @@ sanitizer/common_interface_defs.h sanitizer/coverage_interface.h sanitizer/dfsan_interface.h - sanitizer/esan_interface.h sanitizer/hwasan_interface.h sanitizer/linux_syscall_hooks.h sanitizer/lsan_interface.h Index: compiler-rt/include/sanitizer/esan_interface.h =================================================================== --- compiler-rt/include/sanitizer/esan_interface.h +++ /dev/null @@ -1,49 +0,0 @@ -//===-- sanitizer/esan_interface.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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Public interface header. -//===----------------------------------------------------------------------===// -#ifndef SANITIZER_ESAN_INTERFACE_H -#define SANITIZER_ESAN_INTERFACE_H - -#include - -// We declare our interface routines as weak to allow the user to avoid -// ifdefs and instead use this pattern to allow building the same sources -// with and without our runtime library: -// if (__esan_report) -// __esan_report(); -#ifdef _MSC_VER -/* selectany is as close to weak as we'll get. */ -#define COMPILER_RT_WEAK __declspec(selectany) -#elif __GNUC__ -#define COMPILER_RT_WEAK __attribute__((weak)) -#else -#define COMPILER_RT_WEAK -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// This function can be called mid-run (or at the end of a run for -// a server process that doesn't shut down normally) to request that -// data for that point in the run be reported from the tool. -void COMPILER_RT_WEAK __esan_report(void); - -// This function returns the number of samples that the esan tool has collected -// to this point. This is useful for testing. -unsigned int COMPILER_RT_WEAK __esan_get_sample_count(void); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // SANITIZER_ESAN_INTERFACE_H Index: compiler-rt/lib/esan/CMakeLists.txt =================================================================== --- compiler-rt/lib/esan/CMakeLists.txt +++ /dev/null @@ -1,55 +0,0 @@ -# Build for the EfficiencySanitizer runtime support library. - -add_compiler_rt_component(esan) - -set(ESAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS}) -append_rtti_flag(OFF ESAN_RTL_CFLAGS) - -include_directories(..) - -set(ESAN_SOURCES - esan.cpp - esan_flags.cpp - esan_interface.cpp - esan_interceptors.cpp - esan_linux.cpp - esan_sideline_linux.cpp - esan_sideline_bsd.cpp - cache_frag.cpp - working_set.cpp - working_set_posix.cpp) - -set(ESAN_HEADERS - cache_frag.h - esan.h - esan_circular_buffer.h - esan_flags.h - esan_flags.inc - esan_hashtable.h - esan_interface_internal.h - esan_shadow.h - esan_sideline.h - working_set.h) - -foreach (arch ${ESAN_SUPPORTED_ARCH}) - add_compiler_rt_runtime(clang_rt.esan - STATIC - ARCHS ${arch} - SOURCES ${ESAN_SOURCES} - $ - $ - $ - $ - ADDITIONAL_HEADERS ${ESAN_HEADERS} - CFLAGS ${ESAN_RTL_CFLAGS}) - add_sanitizer_rt_symbols(clang_rt.esan - ARCHS ${arch} - EXTRA esan.syms.extra) - add_dependencies(esan - clang_rt.esan-${arch} - clang_rt.esan-${arch}-symbols) -endforeach() - -if (COMPILER_RT_INCLUDE_TESTS) - # TODO(bruening): add tests via add_subdirectory(tests) -endif() Index: compiler-rt/lib/esan/cache_frag.h =================================================================== --- compiler-rt/lib/esan/cache_frag.h +++ /dev/null @@ -1,28 +0,0 @@ -//===-- cache_frag.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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Header for cache-fragmentation-specific code. -//===----------------------------------------------------------------------===// - -#ifndef CACHE_FRAG_H -#define CACHE_FRAG_H - -namespace __esan { - -void processCacheFragCompilationUnitInit(void *Ptr); -void processCacheFragCompilationUnitExit(void *Ptr); - -void initializeCacheFrag(); -int finalizeCacheFrag(); -void reportCacheFrag(); - -} // namespace __esan - -#endif // CACHE_FRAG_H Index: compiler-rt/lib/esan/cache_frag.cpp =================================================================== --- compiler-rt/lib/esan/cache_frag.cpp +++ /dev/null @@ -1,207 +0,0 @@ -//===-- cache_frag.cpp ----------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// This file contains cache fragmentation-specific code. -//===----------------------------------------------------------------------===// - -#include "esan.h" -#include "esan_flags.h" -#include "sanitizer_common/sanitizer_addrhashmap.h" -#include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_placement_new.h" -#include - -namespace __esan { - -//===-- Struct field access counter runtime -------------------------------===// - -// This should be kept consistent with LLVM's EfficiencySanitizer StructInfo. -struct StructInfo { - const char *StructName; - u32 Size; - u32 NumFields; - u32 *FieldOffset; // auxiliary struct field info. - u32 *FieldSize; // auxiliary struct field info. - const char **FieldTypeName; // auxiliary struct field info. - u64 *FieldCounters; - u64 *ArrayCounter; - bool hasAuxFieldInfo() { return FieldOffset != nullptr; } -}; - -// This should be kept consistent with LLVM's EfficiencySanitizer CacheFragInfo. -// The tool-specific information per compilation unit (module). -struct CacheFragInfo { - const char *UnitName; - u32 NumStructs; - StructInfo *Structs; -}; - -struct StructCounter { - StructInfo *Struct; - u64 Count; // The total access count of the struct. - u64 Ratio; // Difference ratio for the struct layout access. -}; - -// We use StructHashMap to keep track of an unique copy of StructCounter. -typedef AddrHashMap StructHashMap; -struct Context { - StructHashMap StructMap; - u32 NumStructs; - u64 TotalCount; // The total access count of all structs. -}; -static Context *Ctx; - -static void reportStructSummary() { - // FIXME: provide a better struct field access summary report. - Report("%s: total struct field access count = %llu\n", SanitizerToolName, - Ctx->TotalCount); -} - -// FIXME: we are still exploring proper ways to evaluate the difference between -// struct field counts. Currently, we use a simple formula to calculate the -// difference ratio: V1/V2. -static inline u64 computeDifferenceRatio(u64 Val1, u64 Val2) { - if (Val2 > Val1) { - Swap(Val1, Val2); - } - if (Val2 == 0) - Val2 = 1; - return (Val1 / Val2); -} - -static void reportStructCounter(StructHashMap::Handle &Handle) { - const u32 TypePrintLimit = 512; - const char *type, *start, *end; - StructInfo *Struct = Handle->Struct; - // Union field address calculation is done via bitcast instead of GEP, - // so the count for union is always 0. - // We skip the union report to avoid confusion. - if (strncmp(Struct->StructName, "union.", 6) == 0) - return; - // Remove the '.' after class/struct during print. - if (strncmp(Struct->StructName, "class.", 6) == 0) { - type = "class"; - start = &Struct->StructName[6]; - } else { - type = "struct"; - start = &Struct->StructName[7]; - } - // Remove the suffixes with '$' during print. - end = strchr(start, '$'); - CHECK(end != nullptr); - Report(" %s %.*s\n", type, end - start, start); - Report(" size = %u, count = %llu, ratio = %llu, array access = %llu\n", - Struct->Size, Handle->Count, Handle->Ratio, *Struct->ArrayCounter); - if (Struct->hasAuxFieldInfo()) { - for (u32 i = 0; i < Struct->NumFields; ++i) { - Report(" #%2u: offset = %u,\t size = %u," - "\t count = %llu,\t type = %.*s\n", - i, Struct->FieldOffset[i], Struct->FieldSize[i], - Struct->FieldCounters[i], TypePrintLimit, Struct->FieldTypeName[i]); - } - } else { - for (u32 i = 0; i < Struct->NumFields; ++i) { - Report(" #%2u: count = %llu\n", i, Struct->FieldCounters[i]); - } - } -} - -static void computeStructRatio(StructHashMap::Handle &Handle) { - Handle->Ratio = 0; - Handle->Count = Handle->Struct->FieldCounters[0]; - for (u32 i = 1; i < Handle->Struct->NumFields; ++i) { - Handle->Count += Handle->Struct->FieldCounters[i]; - Handle->Ratio += computeDifferenceRatio( - Handle->Struct->FieldCounters[i - 1], Handle->Struct->FieldCounters[i]); - } - Ctx->TotalCount += Handle->Count; - if (Handle->Ratio >= (u64)getFlags()->report_threshold || - (Verbosity() >= 1 && Handle->Count > 0)) - reportStructCounter(Handle); -} - -static void registerStructInfo(CacheFragInfo *CacheFrag) { - for (u32 i = 0; i < CacheFrag->NumStructs; ++i) { - StructInfo *Struct = &CacheFrag->Structs[i]; - StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters); - if (H.created()) { - VPrintf(2, " Register %s: %u fields\n", Struct->StructName, - Struct->NumFields); - H->Struct = Struct; - ++Ctx->NumStructs; - } else { - VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName, - Struct->NumFields); - } - } -} - -static void unregisterStructInfo(CacheFragInfo *CacheFrag) { - // FIXME: if the library is unloaded before finalizeCacheFrag, we should - // collect the result for later report. - for (u32 i = 0; i < CacheFrag->NumStructs; ++i) { - StructInfo *Struct = &CacheFrag->Structs[i]; - StructHashMap::Handle H(&Ctx->StructMap, (uptr)Struct->FieldCounters, true); - if (H.exists()) { - VPrintf(2, " Unregister %s: %u fields\n", Struct->StructName, - Struct->NumFields); - // FIXME: we should move this call to finalizeCacheFrag once we can - // iterate over the hash map there. - computeStructRatio(H); - --Ctx->NumStructs; - } else { - VPrintf(2, " Duplicated %s: %u fields\n", Struct->StructName, - Struct->NumFields); - } - } - static bool Reported = false; - if (Ctx->NumStructs == 0 && !Reported) { - Reported = true; - reportStructSummary(); - } -} - -//===-- Init/exit functions -----------------------------------------------===// - -void processCacheFragCompilationUnitInit(void *Ptr) { - CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr; - VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__, - CacheFrag->UnitName, CacheFrag->NumStructs); - registerStructInfo(CacheFrag); -} - -void processCacheFragCompilationUnitExit(void *Ptr) { - CacheFragInfo *CacheFrag = (CacheFragInfo *)Ptr; - VPrintf(2, "in esan::%s: %s with %u class(es)/struct(s)\n", __FUNCTION__, - CacheFrag->UnitName, CacheFrag->NumStructs); - unregisterStructInfo(CacheFrag); -} - -void initializeCacheFrag() { - VPrintf(2, "in esan::%s\n", __FUNCTION__); - // We use placement new to initialize Ctx before C++ static initializaion. - // We make CtxMem 8-byte aligned for atomic operations in AddrHashMap. - static u64 CtxMem[sizeof(Context) / sizeof(u64) + 1]; - Ctx = new (CtxMem) Context(); - Ctx->NumStructs = 0; -} - -int finalizeCacheFrag() { - VPrintf(2, "in esan::%s\n", __FUNCTION__); - return 0; -} - -void reportCacheFrag() { - VPrintf(2, "in esan::%s\n", __FUNCTION__); - // FIXME: Not yet implemented. We need to iterate over all of the - // compilation unit data. -} - -} // namespace __esan Index: compiler-rt/lib/esan/esan.h =================================================================== --- compiler-rt/lib/esan/esan.h +++ /dev/null @@ -1,60 +0,0 @@ -//===-- esan.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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Main internal esan header file. -// -// Ground rules: -// - C++ run-time should not be used (static CTORs, RTTI, exceptions, static -// function-scope locals) -// - All functions/classes/etc reside in namespace __esan, except for those -// declared in esan_interface_internal.h. -// - Platform-specific files should be used instead of ifdefs (*). -// - No system headers included in header files (*). -// - Platform specific headers included only into platform-specific files (*). -// -// (*) Except when inlining is critical for performance. -//===----------------------------------------------------------------------===// - -#ifndef ESAN_H -#define ESAN_H - -#include "interception/interception.h" -#include "sanitizer_common/sanitizer_common.h" -#include "esan_interface_internal.h" - -namespace __esan { - -extern bool EsanIsInitialized; -extern bool EsanDuringInit; -extern uptr VmaSize; - -void initializeLibrary(ToolType Tool); -int finalizeLibrary(); -void reportResults(); -unsigned int getSampleCount(); -// Esan creates the variable per tool per compilation unit at compile time -// and passes its pointer Ptr to the runtime library. -void processCompilationUnitInit(void *Ptr); -void processCompilationUnitExit(void *Ptr); -void processRangeAccess(uptr PC, uptr Addr, int Size, bool IsWrite); -void initializeInterceptors(); - -// Platform-dependent routines. -void verifyAddressSpace(); -bool fixMmapAddr(void **Addr, SIZE_T Size, int Flags); -uptr checkMmapResult(uptr Addr, SIZE_T Size); -// The return value indicates whether to call the real version or not. -bool processSignal(int SigNum, void (*Handler)(int), void (**Result)(int)); -bool processSigaction(int SigNum, const void *Act, void *OldAct); -bool processSigprocmask(int How, void *Set, void *OldSet); - -} // namespace __esan - -#endif // ESAN_H Index: compiler-rt/lib/esan/esan.cpp =================================================================== --- compiler-rt/lib/esan/esan.cpp +++ /dev/null @@ -1,277 +0,0 @@ -//===-- esan.cpp ----------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Main file (entry points) for the Esan run-time. -//===----------------------------------------------------------------------===// - -#include "esan.h" -#include "esan_flags.h" -#include "esan_interface_internal.h" -#include "esan_shadow.h" -#include "cache_frag.h" -#include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_flag_parser.h" -#include "sanitizer_common/sanitizer_flags.h" -#include "working_set.h" - -// See comment below. -extern "C" { -extern void __cxa_atexit(void (*function)(void)); -} - -namespace __esan { - -bool EsanIsInitialized; -bool EsanDuringInit; -ShadowMapping Mapping; - -// Different tools use different scales within the same shadow mapping scheme. -// The scale used here must match that used by the compiler instrumentation. -// This array is indexed by the ToolType enum. -static const uptr ShadowScale[] = { - 0, // ESAN_None. - 2, // ESAN_CacheFrag: 4B:1B, so 4 to 1 == >>2. - 6, // ESAN_WorkingSet: 64B:1B, so 64 to 1 == >>6. -}; - -// We are combining multiple performance tuning tools under the umbrella of -// one EfficiencySanitizer super-tool. Most of our tools have very similar -// memory access instrumentation, shadow memory mapping, libc interception, -// etc., and there is typically more shared code than distinct code. -// -// We are not willing to dispatch on tool dynamically in our fastpath -// instrumentation: thus, which tool to use is a static option selected -// at compile time and passed to __esan_init(). -// -// We are willing to pay the overhead of tool dispatch in the slowpath to more -// easily share code. We expect to only come here rarely. -// If this becomes a performance hit, we can add separate interface -// routines for each subtool (e.g., __esan_cache_frag_aligned_load_4). -// But for libc interceptors, we'll have to do one of the following: -// A) Add multiple-include support to sanitizer_common_interceptors.inc, -// instantiate it separately for each tool, and call the selected -// tool's intercept setup code. -// B) Build separate static runtime libraries, one for each tool. -// C) Completely split the tools into separate sanitizers. - -void processRangeAccess(uptr PC, uptr Addr, int Size, bool IsWrite) { - VPrintf(3, "in esan::%s %p: %c %p %d\n", __FUNCTION__, PC, - IsWrite ? 'w' : 'r', Addr, Size); - if (__esan_which_tool == ESAN_CacheFrag) { - // TODO(bruening): add shadow mapping and update shadow bits here. - // We'll move this to cache_frag.cpp once we have something. - } else if (__esan_which_tool == ESAN_WorkingSet) { - processRangeAccessWorkingSet(PC, Addr, Size, IsWrite); - } -} - -bool processSignal(int SigNum, void (*Handler)(int), void (**Result)(int)) { - if (__esan_which_tool == ESAN_WorkingSet) - return processWorkingSetSignal(SigNum, Handler, Result); - return true; -} - -bool processSigaction(int SigNum, const void *Act, void *OldAct) { - if (__esan_which_tool == ESAN_WorkingSet) - return processWorkingSetSigaction(SigNum, Act, OldAct); - return true; -} - -bool processSigprocmask(int How, void *Set, void *OldSet) { - if (__esan_which_tool == ESAN_WorkingSet) - return processWorkingSetSigprocmask(How, Set, OldSet); - return true; -} - -#if SANITIZER_DEBUG -static bool verifyShadowScheme() { - // Sanity checks for our shadow mapping scheme. - uptr AppStart, AppEnd; - if (Verbosity() >= 3) { - for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) { - VPrintf(3, "App #%d: [%zx-%zx) (%zuGB)\n", i, AppStart, AppEnd, - (AppEnd - AppStart) >> 30); - } - } - for (int Scale = 0; Scale < 8; ++Scale) { - Mapping.initialize(Scale); - if (Verbosity() >= 3) { - VPrintf(3, "\nChecking scale %d\n", Scale); - uptr ShadowStart, ShadowEnd; - for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) { - VPrintf(3, "Shadow #%d: [%zx-%zx) (%zuGB)\n", i, ShadowStart, - ShadowEnd, (ShadowEnd - ShadowStart) >> 30); - } - for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) { - VPrintf(3, "Shadow(Shadow) #%d: [%zx-%zx)\n", i, - appToShadow(ShadowStart), appToShadow(ShadowEnd - 1)+1); - } - } - for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) { - DCHECK(isAppMem(AppStart)); - DCHECK(!isAppMem(AppStart - 1)); - DCHECK(isAppMem(AppEnd - 1)); - DCHECK(!isAppMem(AppEnd)); - DCHECK(!isShadowMem(AppStart)); - DCHECK(!isShadowMem(AppEnd - 1)); - DCHECK(isShadowMem(appToShadow(AppStart))); - DCHECK(isShadowMem(appToShadow(AppEnd - 1))); - // Double-shadow checks. - DCHECK(!isShadowMem(appToShadow(appToShadow(AppStart)))); - DCHECK(!isShadowMem(appToShadow(appToShadow(AppEnd - 1)))); - } - // Ensure no shadow regions overlap each other. - uptr ShadowAStart, ShadowBStart, ShadowAEnd, ShadowBEnd; - for (int i = 0; getShadowRegion(i, &ShadowAStart, &ShadowAEnd); ++i) { - for (int j = 0; getShadowRegion(j, &ShadowBStart, &ShadowBEnd); ++j) { - DCHECK(i == j || ShadowAStart >= ShadowBEnd || - ShadowAEnd <= ShadowBStart); - } - } - } - return true; -} -#endif - -uptr VmaSize; - -static void initializeShadow() { - verifyAddressSpace(); - - // This is based on the assumption that the intial stack is always allocated - // in the topmost segment of the user address space and the assumption - // holds true on all the platforms currently supported. - VmaSize = - (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1); - - DCHECK(verifyShadowScheme()); - - Mapping.initialize(ShadowScale[__esan_which_tool]); - - VPrintf(1, "Shadow scale=%d offset=%p\n", Mapping.Scale, Mapping.Offset); - - uptr ShadowStart, ShadowEnd; - for (int i = 0; getShadowRegion(i, &ShadowStart, &ShadowEnd); ++i) { - VPrintf(1, "Shadow #%d: [%zx-%zx) (%zuGB)\n", i, ShadowStart, ShadowEnd, - (ShadowEnd - ShadowStart) >> 30); - - uptr Map = 0; - if (__esan_which_tool == ESAN_WorkingSet) { - // We want to identify all shadow pages that are touched so we start - // out inaccessible. - Map = (uptr)MmapFixedNoAccess(ShadowStart, ShadowEnd- ShadowStart, - "shadow"); - } else { - if (MmapFixedNoReserve(ShadowStart, ShadowEnd - ShadowStart, "shadow")) - Map = ShadowStart; - } - if (Map != ShadowStart) { - Printf("FATAL: EfficiencySanitizer failed to map its shadow memory.\n"); - Die(); - } - - if (common_flags()->no_huge_pages_for_shadow) - NoHugePagesInRegion(ShadowStart, ShadowEnd - ShadowStart); - if (common_flags()->use_madv_dontdump) - DontDumpShadowMemory(ShadowStart, ShadowEnd - ShadowStart); - - // TODO: Call MmapNoAccess() on in-between regions. - } -} - -void initializeLibrary(ToolType Tool) { - // We assume there is only one thread during init, but we need to - // guard against double-init when we're (re-)called from an - // early interceptor. - if (EsanIsInitialized || EsanDuringInit) - return; - EsanDuringInit = true; - CHECK(Tool == __esan_which_tool); - SanitizerToolName = "EfficiencySanitizer"; - CacheBinaryName(); - initializeFlags(); - - // Intercepting libc _exit or exit via COMMON_INTERCEPTOR_ON_EXIT only - // finalizes on an explicit exit call by the app. To handle a normal - // exit we register an atexit handler. - ::__cxa_atexit((void (*)())finalizeLibrary); - - VPrintf(1, "in esan::%s\n", __FUNCTION__); - if (__esan_which_tool <= ESAN_None || __esan_which_tool >= ESAN_Max) { - Printf("ERROR: unknown tool %d requested\n", __esan_which_tool); - Die(); - } - - initializeShadow(); - if (__esan_which_tool == ESAN_WorkingSet) - initializeShadowWorkingSet(); - - initializeInterceptors(); - - if (__esan_which_tool == ESAN_CacheFrag) { - initializeCacheFrag(); - } else if (__esan_which_tool == ESAN_WorkingSet) { - initializeWorkingSet(); - } - - EsanIsInitialized = true; - EsanDuringInit = false; -} - -int finalizeLibrary() { - VPrintf(1, "in esan::%s\n", __FUNCTION__); - if (__esan_which_tool == ESAN_CacheFrag) { - return finalizeCacheFrag(); - } else if (__esan_which_tool == ESAN_WorkingSet) { - return finalizeWorkingSet(); - } - return 0; -} - -void reportResults() { - VPrintf(1, "in esan::%s\n", __FUNCTION__); - if (__esan_which_tool == ESAN_CacheFrag) { - return reportCacheFrag(); - } else if (__esan_which_tool == ESAN_WorkingSet) { - return reportWorkingSet(); - } -} - -void processCompilationUnitInit(void *Ptr) { - VPrintf(2, "in esan::%s\n", __FUNCTION__); - if (__esan_which_tool == ESAN_CacheFrag) { - DCHECK(Ptr != nullptr); - processCacheFragCompilationUnitInit(Ptr); - } else { - DCHECK(Ptr == nullptr); - } -} - -// This is called when the containing module is unloaded. -// For the main executable module, this is called after finalizeLibrary. -void processCompilationUnitExit(void *Ptr) { - VPrintf(2, "in esan::%s\n", __FUNCTION__); - if (__esan_which_tool == ESAN_CacheFrag) { - DCHECK(Ptr != nullptr); - processCacheFragCompilationUnitExit(Ptr); - } else { - DCHECK(Ptr == nullptr); - } -} - -unsigned int getSampleCount() { - VPrintf(1, "in esan::%s\n", __FUNCTION__); - if (__esan_which_tool == ESAN_WorkingSet) { - return getSampleCountWorkingSet(); - } - return 0; -} - -} // namespace __esan Index: compiler-rt/lib/esan/esan.syms.extra =================================================================== --- compiler-rt/lib/esan/esan.syms.extra +++ /dev/null @@ -1,4 +0,0 @@ -__esan_init -__esan_exit -__esan_aligned* -__esan_unaligned* Index: compiler-rt/lib/esan/esan_circular_buffer.h =================================================================== --- compiler-rt/lib/esan/esan_circular_buffer.h +++ /dev/null @@ -1,95 +0,0 @@ -//===-- esan_circular_buffer.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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Circular buffer data structure. -//===----------------------------------------------------------------------===// - -#include "sanitizer_common/sanitizer_common.h" - -namespace __esan { - -// A circular buffer for POD data whose memory is allocated using mmap. -// There are two usage models: one is to use initialize/free (for global -// instances) and the other is to use placement new with the -// constructor and to call the destructor or free (they are equivalent). -template -class CircularBuffer { - public: - // To support global instances we cannot initialize any field in the - // default constructor. - explicit CircularBuffer() {} - CircularBuffer(uptr BufferCapacity) { - initialize(BufferCapacity); - WasConstructed = true; - } - ~CircularBuffer() { - if (WasConstructed) // Else caller will call free() explicitly. - free(); - } - void initialize(uptr BufferCapacity) { - Capacity = BufferCapacity; - // MmapOrDie rounds up to the page size for us. - Data = (T *)MmapOrDie(Capacity * sizeof(T), "CircularBuffer"); - StartIdx = 0; - Count = 0; - WasConstructed = false; - } - void free() { - UnmapOrDie(Data, Capacity * sizeof(T)); - } - T &operator[](uptr Idx) { - CHECK_LT(Idx, Count); - uptr ArrayIdx = (StartIdx + Idx) % Capacity; - return Data[ArrayIdx]; - } - const T &operator[](uptr Idx) const { - CHECK_LT(Idx, Count); - uptr ArrayIdx = (StartIdx + Idx) % Capacity; - return Data[ArrayIdx]; - } - void push_back(const T &Item) { - CHECK_GT(Capacity, 0); - uptr ArrayIdx = (StartIdx + Count) % Capacity; - Data[ArrayIdx] = Item; - if (Count < Capacity) - ++Count; - else - StartIdx = (StartIdx + 1) % Capacity; - } - T &back() { - CHECK_GT(Count, 0); - uptr ArrayIdx = (StartIdx + Count - 1) % Capacity; - return Data[ArrayIdx]; - } - void pop_back() { - CHECK_GT(Count, 0); - --Count; - } - uptr size() const { - return Count; - } - void clear() { - StartIdx = 0; - Count = 0; - } - bool empty() const { return size() == 0; } - - private: - CircularBuffer(const CircularBuffer&); - void operator=(const CircularBuffer&); - - bool WasConstructed; - T *Data; - uptr Capacity; - uptr StartIdx; - uptr Count; -}; - -} // namespace __esan Index: compiler-rt/lib/esan/esan_flags.h =================================================================== --- compiler-rt/lib/esan/esan_flags.h +++ /dev/null @@ -1,40 +0,0 @@ -//===-- esan_flags.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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Esan runtime flags. -//===----------------------------------------------------------------------===// - -#ifndef ESAN_FLAGS_H -#define ESAN_FLAGS_H - -#include "sanitizer_common/sanitizer_internal_defs.h" -#include "sanitizer_common/sanitizer_flag_parser.h" - -namespace __esan { - -class Flags { -public: -#define ESAN_FLAG(Type, Name, DefaultValue, Description) Type Name; -#include "esan_flags.inc" -#undef ESAN_FLAG - - void setDefaults(); -}; - -extern Flags EsanFlagsDontUseDirectly; -inline Flags *getFlags() { - return &EsanFlagsDontUseDirectly; -} - -void initializeFlags(); - -} // namespace __esan - -#endif // ESAN_FLAGS_H Index: compiler-rt/lib/esan/esan_flags.cpp =================================================================== --- compiler-rt/lib/esan/esan_flags.cpp +++ /dev/null @@ -1,59 +0,0 @@ -//===-- esan_flags.cc -------------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Esan flag parsing logic. -//===----------------------------------------------------------------------===// - -#include "esan_flags.h" -#include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_flag_parser.h" -#include "sanitizer_common/sanitizer_flags.h" - -using namespace __sanitizer; - -namespace __esan { - -static const char EsanOptsEnv[] = "ESAN_OPTIONS"; - -Flags EsanFlagsDontUseDirectly; - -void Flags::setDefaults() { -#define ESAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; -#include "esan_flags.inc" -#undef ESAN_FLAG -} - -static void registerEsanFlags(FlagParser *Parser, Flags *F) { -#define ESAN_FLAG(Type, Name, DefaultValue, Description) \ - RegisterFlag(Parser, #Name, Description, &F->Name); -#include "esan_flags.inc" -#undef ESAN_FLAG -} - -void initializeFlags() { - SetCommonFlagsDefaults(); - Flags *F = getFlags(); - F->setDefaults(); - - FlagParser Parser; - registerEsanFlags(&Parser, F); - RegisterCommonFlags(&Parser); - Parser.ParseString(GetEnv(EsanOptsEnv)); - - InitializeCommonFlags(); - if (Verbosity()) - ReportUnrecognizedFlags(); - if (common_flags()->help) - Parser.PrintFlagDescriptions(); - - __sanitizer_set_report_path(common_flags()->log_path); -} - -} // namespace __esan Index: compiler-rt/lib/esan/esan_flags.inc =================================================================== --- compiler-rt/lib/esan/esan_flags.inc +++ /dev/null @@ -1,55 +0,0 @@ -//===-- esan_flags.inc ------------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// -// -// Esan runtime flags. -// -//===----------------------------------------------------------------------===// - -#ifndef ESAN_FLAG -# error "Define ESAN_FLAG prior to including this file!" -#endif - -// ESAN_FLAG(Type, Name, DefaultValue, Description) -// See COMMON_FLAG in sanitizer_flags.inc for more details. - -//===----------------------------------------------------------------------===// -// Cross-tool options -//===----------------------------------------------------------------------===// - -ESAN_FLAG(int, cache_line_size, 64, - "The number of bytes in a cache line. For the working-set tool, this " - "cannot be changed without also changing the compiler " - "instrumentation.") - -//===----------------------------------------------------------------------===// -// Working set tool options -//===----------------------------------------------------------------------===// - -ESAN_FLAG(bool, record_snapshots, true, - "Working set tool: whether to sample snapshots during a run.") - -// Typical profiling uses a 10ms timer. Our snapshots take some work -// to scan memory so we reduce to 20ms. -// To disable samples, turn off record_snapshots. -ESAN_FLAG(int, sample_freq, 20, - "Working set tool: sampling frequency in milliseconds.") - -// This controls the difference in frequency between each successive series -// of snapshots. There are 8 in total, with number 0 using sample_freq. -// Number N samples number N-1 every (1 << snapshot_step) instance of N-1. -ESAN_FLAG(int, snapshot_step, 2, "Working set tool: the log of the sampling " - "performed for the next-higher-frequency snapshot series.") - -//===----------------------------------------------------------------------===// -// Cache Fragmentation tool options -//===----------------------------------------------------------------------===// - -// The difference information of a struct is reported if the struct's difference -// score is greater than the report_threshold. -ESAN_FLAG(int, report_threshold, 1<<10, "Cache-frag tool: the struct difference" - " score threshold for reporting.") Index: compiler-rt/lib/esan/esan_hashtable.h =================================================================== --- compiler-rt/lib/esan/esan_hashtable.h +++ /dev/null @@ -1,380 +0,0 @@ -//===-- esan_hashtable.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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Generic resizing hashtable. -//===----------------------------------------------------------------------===// - -#include "sanitizer_common/sanitizer_allocator_internal.h" -#include "sanitizer_common/sanitizer_internal_defs.h" -#include "sanitizer_common/sanitizer_mutex.h" -#include - -namespace __esan { - -//===----------------------------------------------------------------------===// -// Default hash and comparison functions -//===----------------------------------------------------------------------===// - -template struct DefaultHash { - size_t operator()(const T &Key) const { - return (size_t)Key; - } -}; - -template struct DefaultEqual { - bool operator()(const T &Key1, const T &Key2) const { - return Key1 == Key2; - } -}; - -//===----------------------------------------------------------------------===// -// HashTable declaration -//===----------------------------------------------------------------------===// - -// A simple resizing and mutex-locked hashtable. -// -// If the default hash functor is used, KeyTy must have an operator size_t(). -// If the default comparison functor is used, KeyTy must have an operator ==. -// -// By default all operations are internally-synchronized with a mutex, with no -// synchronization for payloads once hashtable functions return. If -// ExternalLock is set to true, the caller should call the lock() and unlock() -// routines around all hashtable operations and subsequent manipulation of -// payloads. -template , - typename EqualFuncTy = DefaultEqual > -class HashTable { -public: - // InitialCapacity must be a power of 2. - // ResizeFactor must be between 1 and 99 and indicates the - // maximum percentage full that the table should ever be. - HashTable(u32 InitialCapacity = 2048, u32 ResizeFactor = 70); - ~HashTable(); - bool lookup(const KeyTy &Key, DataTy &Payload); // Const except for Mutex. - bool add(const KeyTy &Key, const DataTy &Payload); - bool remove(const KeyTy &Key); - u32 size(); // Const except for Mutex. - // If the table is internally-synchronized, this lock must not be held - // while a hashtable function is called as it will deadlock: the lock - // is not recursive. This is meant for use with externally-synchronized - // tables or with an iterator. - void lock(); - void unlock(); - -private: - struct HashEntry { - KeyTy Key; - DataTy Payload; - HashEntry *Next; - }; - -public: - struct HashPair { - HashPair(KeyTy Key, DataTy Data) : Key(Key), Data(Data) {} - KeyTy Key; - DataTy Data; - }; - - // This iterator does not perform any synchronization. - // It expects the caller to lock the table across the whole iteration. - // Calling HashTable functions while using the iterator is not supported. - // The iterator returns copies of the keys and data. - class iterator { - public: - iterator( - HashTable *Table); - iterator(const iterator &Src) = default; - iterator &operator=(const iterator &Src) = default; - HashPair operator*(); - iterator &operator++(); - iterator &operator++(int); - bool operator==(const iterator &Cmp) const; - bool operator!=(const iterator &Cmp) const; - - private: - iterator( - HashTable *Table, - int Idx); - friend HashTable; - HashTable *Table; - int Idx; - HashTable::HashEntry - *Entry; - }; - - // No erase or insert iterator supported - iterator begin(); - iterator end(); - -private: - void resize(); - - HashEntry **Table; - u32 Capacity; - u32 Entries; - const u32 ResizeFactor; - BlockingMutex Mutex; - const HashFuncTy HashFunc; - const EqualFuncTy EqualFunc; -}; - -//===----------------------------------------------------------------------===// -// Hashtable implementation -//===----------------------------------------------------------------------===// - -template -HashTable::HashTable( - u32 InitialCapacity, u32 ResizeFactor) - : Capacity(InitialCapacity), Entries(0), ResizeFactor(ResizeFactor), - HashFunc(HashFuncTy()), EqualFunc(EqualFuncTy()) { - CHECK(IsPowerOfTwo(Capacity)); - CHECK(ResizeFactor >= 1 && ResizeFactor <= 99); - Table = (HashEntry **)InternalAlloc(Capacity * sizeof(HashEntry *)); - internal_memset(Table, 0, Capacity * sizeof(HashEntry *)); -} - -template -HashTable::~HashTable() { - for (u32 i = 0; i < Capacity; ++i) { - HashEntry *Entry = Table[i]; - while (Entry != nullptr) { - HashEntry *Next = Entry->Next; - Entry->Payload.~DataTy(); - InternalFree(Entry); - Entry = Next; - } - } - InternalFree(Table); -} - -template -u32 HashTable::size() { - u32 Res; - if (!ExternalLock) - Mutex.Lock(); - Res = Entries; - if (!ExternalLock) - Mutex.Unlock(); - return Res; -} - -template -bool HashTable::lookup( - const KeyTy &Key, DataTy &Payload) { - if (!ExternalLock) - Mutex.Lock(); - bool Found = false; - size_t Hash = HashFunc(Key) % Capacity; - HashEntry *Entry = Table[Hash]; - for (; Entry != nullptr; Entry = Entry->Next) { - if (EqualFunc(Entry->Key, Key)) { - Payload = Entry->Payload; - Found = true; - break; - } - } - if (!ExternalLock) - Mutex.Unlock(); - return Found; -} - -template -void HashTable::resize() { - if (!ExternalLock) - Mutex.CheckLocked(); - size_t OldCapacity = Capacity; - HashEntry **OldTable = Table; - Capacity *= 2; - Table = (HashEntry **)InternalAlloc(Capacity * sizeof(HashEntry *)); - internal_memset(Table, 0, Capacity * sizeof(HashEntry *)); - // Re-hash - for (u32 i = 0; i < OldCapacity; ++i) { - HashEntry *OldEntry = OldTable[i]; - while (OldEntry != nullptr) { - HashEntry *Next = OldEntry->Next; - size_t Hash = HashFunc(OldEntry->Key) % Capacity; - OldEntry->Next = Table[Hash]; - Table[Hash] = OldEntry; - OldEntry = Next; - } - } -} - -template -bool HashTable::add( - const KeyTy &Key, const DataTy &Payload) { - if (!ExternalLock) - Mutex.Lock(); - bool Exists = false; - size_t Hash = HashFunc(Key) % Capacity; - HashEntry *Entry = Table[Hash]; - for (; Entry != nullptr; Entry = Entry->Next) { - if (EqualFunc(Entry->Key, Key)) { - Exists = true; - break; - } - } - if (!Exists) { - Entries++; - if (Entries * 100 >= Capacity * ResizeFactor) { - resize(); - Hash = HashFunc(Key) % Capacity; - } - HashEntry *Add = (HashEntry *)InternalAlloc(sizeof(*Add)); - Add->Key = Key; - Add->Payload = Payload; - Add->Next = Table[Hash]; - Table[Hash] = Add; - } - if (!ExternalLock) - Mutex.Unlock(); - return !Exists; -} - -template -bool HashTable::remove( - const KeyTy &Key) { - if (!ExternalLock) - Mutex.Lock(); - bool Found = false; - size_t Hash = HashFunc(Key) % Capacity; - HashEntry *Entry = Table[Hash]; - HashEntry *Prev = nullptr; - for (; Entry != nullptr; Prev = Entry, Entry = Entry->Next) { - if (EqualFunc(Entry->Key, Key)) { - Found = true; - Entries--; - if (Prev == nullptr) - Table[Hash] = Entry->Next; - else - Prev->Next = Entry->Next; - Entry->Payload.~DataTy(); - InternalFree(Entry); - break; - } - } - if (!ExternalLock) - Mutex.Unlock(); - return Found; -} - -template -void HashTable::lock() { - Mutex.Lock(); -} - -template -void HashTable::unlock() { - Mutex.Unlock(); -} - -//===----------------------------------------------------------------------===// -// Iterator implementation -//===----------------------------------------------------------------------===// - -template -HashTable::iterator:: - iterator( - HashTable *Table) - : Table(Table), Idx(-1), Entry(nullptr) { - operator++(); -} - -template -HashTable::iterator:: - iterator( - HashTable *Table, - int Idx) - : Table(Table), Idx(Idx), Entry(nullptr) { - CHECK(Idx >= (int)Table->Capacity); // Only used to create end(). -} - -template -typename HashTable::HashPair - HashTable::iterator:: - operator*() { - CHECK(Idx >= 0 && Idx < (int)Table->Capacity); - CHECK(Entry != nullptr); - return HashPair(Entry->Key, Entry->Payload); -} - -template -typename HashTable::iterator & - HashTable::iterator:: - operator++() { - if (Entry != nullptr) - Entry = Entry->Next; - while (Entry == nullptr) { - ++Idx; - if (Idx >= (int)Table->Capacity) - break; // At end(). - Entry = Table->Table[Idx]; - } - return *this; -} - -template -typename HashTable::iterator & - HashTable::iterator:: - operator++(int) { - iterator Temp(*this); - operator++(); - return Temp; -} - -template -bool HashTable::iterator:: -operator==(const iterator &Cmp) const { - return Cmp.Table == Table && Cmp.Idx == Idx && Cmp.Entry == Entry; -} - -template -bool HashTable::iterator:: -operator!=(const iterator &Cmp) const { - return Cmp.Table != Table || Cmp.Idx != Idx || Cmp.Entry != Entry; -} - -template -typename HashTable::iterator -HashTable::begin() { - return iterator(this); -} - -template -typename HashTable::iterator -HashTable::end() { - return iterator(this, Capacity); -} - -} // namespace __esan Index: compiler-rt/lib/esan/esan_interceptors.cpp =================================================================== --- compiler-rt/lib/esan/esan_interceptors.cpp +++ /dev/null @@ -1,512 +0,0 @@ -//===-- esan_interceptors.cpp ---------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Interception routines for the esan run-time. -//===----------------------------------------------------------------------===// - -#include "esan.h" -#include "esan_shadow.h" -#include "interception/interception.h" -#include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_libc.h" -#include "sanitizer_common/sanitizer_linux.h" -#include "sanitizer_common/sanitizer_stacktrace.h" - -using namespace __esan; // NOLINT - -#define CUR_PC() (StackTrace::GetCurrentPc()) - -//===----------------------------------------------------------------------===// -// Interception via sanitizer common interceptors -//===----------------------------------------------------------------------===// - -// Get the per-platform defines for what is possible to intercept -#include "sanitizer_common/sanitizer_platform_interceptors.h" - -DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr) - -// TODO(bruening): tsan disables several interceptors (getpwent, etc.) claiming -// that interception is a perf hit: should we do the same? - -// We have no need to intercept: -#undef SANITIZER_INTERCEPT_TLS_GET_ADDR - -// TODO(bruening): the common realpath interceptor assumes malloc is -// intercepted! We should try to parametrize that, though we'll -// intercept malloc soon ourselves and can then remove this undef. -#undef SANITIZER_INTERCEPT_REALPATH - -// We provide our own version: -#undef SANITIZER_INTERCEPT_SIGPROCMASK -#undef SANITIZER_INTERCEPT_PTHREAD_SIGMASK - -#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!EsanIsInitialized) - -#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) -#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ - INTERCEPT_FUNCTION_VER(name, ver) - -// We must initialize during early interceptors, to support tcmalloc. -// This means that for some apps we fully initialize prior to -// __esan_init() being called. -// We currently do not use ctx. -#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ - do { \ - if (UNLIKELY(COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)) { \ - if (!UNLIKELY(EsanDuringInit)) \ - initializeLibrary(__esan_which_tool); \ - return REAL(func)(__VA_ARGS__); \ - } \ - ctx = nullptr; \ - (void)ctx; \ - } while (false) - -#define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, func, ...) \ - COMMON_INTERCEPTOR_ENTER(ctx, func, __VA_ARGS__) - -#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ - processRangeAccess(CUR_PC(), (uptr)ptr, size, true) - -#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ - processRangeAccess(CUR_PC(), (uptr)ptr, size, false) - -// This is only called if the app explicitly calls exit(), not on -// a normal exit. -#define COMMON_INTERCEPTOR_ON_EXIT(ctx) finalizeLibrary() - -#define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) \ - do { \ - (void)(ctx); \ - (void)(file); \ - (void)(path); \ - } while (false) -#define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) \ - do { \ - (void)(ctx); \ - (void)(file); \ - } while (false) -#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ - do { \ - (void)(filename); \ - (void)(handle); \ - } while (false) -#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() \ - do { \ - } while (false) -#define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) \ - do { \ - (void)(ctx); \ - (void)(u); \ - } while (false) -#define COMMON_INTERCEPTOR_RELEASE(ctx, u) \ - do { \ - (void)(ctx); \ - (void)(u); \ - } while (false) -#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ - do { \ - (void)(ctx); \ - (void)(path); \ - } while (false) -#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ - do { \ - (void)(ctx); \ - (void)(fd); \ - } while (false) -#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ - do { \ - (void)(ctx); \ - (void)(fd); \ - } while (false) -#define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) \ - do { \ - (void)(ctx); \ - (void)(fd); \ - } while (false) -#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ - do { \ - (void)(ctx); \ - (void)(fd); \ - (void)(newfd); \ - } while (false) -#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \ - do { \ - (void)(ctx); \ - (void)(name); \ - } while (false) -#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ - do { \ - (void)(ctx); \ - (void)(thread); \ - (void)(name); \ - } while (false) -#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) -#define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) \ - do { \ - (void)(ctx); \ - (void)(m); \ - } while (false) -#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) \ - do { \ - (void)(ctx); \ - (void)(m); \ - } while (false) -#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) \ - do { \ - (void)(ctx); \ - (void)(m); \ - } while (false) -#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \ - do { \ - (void)(ctx); \ - (void)(msg); \ - } while (false) -#define COMMON_INTERCEPTOR_USER_CALLBACK_START() \ - do { \ - } while (false) -#define COMMON_INTERCEPTOR_USER_CALLBACK_END() \ - do { \ - } while (false) - -#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd, \ - off) \ - do { \ - if (!fixMmapAddr(&addr, sz, flags)) \ - return (void *)-1; \ - void *result = REAL(mmap)(addr, sz, prot, flags, fd, off); \ - return (void *)checkMmapResult((uptr)result, sz); \ - } while (false) - -#include "sanitizer_common/sanitizer_common_interceptors.inc" - -//===----------------------------------------------------------------------===// -// Syscall interception -//===----------------------------------------------------------------------===// - -// We want the caller's PC b/c unlike the other function interceptors these -// are separate pre and post functions called around the app's syscall(). - -#define COMMON_SYSCALL_PRE_READ_RANGE(ptr, size) \ - processRangeAccess(GET_CALLER_PC(), (uptr)ptr, size, false) - -#define COMMON_SYSCALL_PRE_WRITE_RANGE(ptr, size) \ - do { \ - (void)(ptr); \ - (void)(size); \ - } while (false) - -#define COMMON_SYSCALL_POST_READ_RANGE(ptr, size) \ - do { \ - (void)(ptr); \ - (void)(size); \ - } while (false) - -// The actual amount written is in post, not pre. -#define COMMON_SYSCALL_POST_WRITE_RANGE(ptr, size) \ - processRangeAccess(GET_CALLER_PC(), (uptr)ptr, size, true) - -#define COMMON_SYSCALL_ACQUIRE(addr) \ - do { \ - (void)(addr); \ - } while (false) -#define COMMON_SYSCALL_RELEASE(addr) \ - do { \ - (void)(addr); \ - } while (false) -#define COMMON_SYSCALL_FD_CLOSE(fd) \ - do { \ - (void)(fd); \ - } while (false) -#define COMMON_SYSCALL_FD_ACQUIRE(fd) \ - do { \ - (void)(fd); \ - } while (false) -#define COMMON_SYSCALL_FD_RELEASE(fd) \ - do { \ - (void)(fd); \ - } while (false) -#define COMMON_SYSCALL_PRE_FORK() \ - do { \ - } while (false) -#define COMMON_SYSCALL_POST_FORK(res) \ - do { \ - (void)(res); \ - } while (false) - -#include "sanitizer_common/sanitizer_common_syscalls.inc" -#include "sanitizer_common/sanitizer_syscalls_netbsd.inc" - -//===----------------------------------------------------------------------===// -// Custom interceptors -//===----------------------------------------------------------------------===// - -// TODO(bruening): move more of these to the common interception pool as they -// are shared with tsan and asan. -// While our other files match LLVM style, here we match sanitizer style as we -// expect to move these to the common pool. - -INTERCEPTOR(char *, strcpy, char *dst, const char *src) { // NOLINT - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, strcpy, dst, src); - uptr srclen = internal_strlen(src); - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, srclen + 1); - COMMON_INTERCEPTOR_READ_RANGE(ctx, src, srclen + 1); - return REAL(strcpy)(dst, src); // NOLINT -} - -INTERCEPTOR(char *, strncpy, char *dst, char *src, uptr n) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, strncpy, dst, src, n); - uptr srclen = internal_strnlen(src, n); - uptr copied_size = srclen + 1 > n ? n : srclen + 1; - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, copied_size); - COMMON_INTERCEPTOR_READ_RANGE(ctx, src, copied_size); - return REAL(strncpy)(dst, src, n); -} - -INTERCEPTOR(int, open, const char *name, int flags, int mode) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, open, name, flags, mode); - COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); - return REAL(open)(name, flags, mode); -} - -#if SANITIZER_LINUX -INTERCEPTOR(int, open64, const char *name, int flags, int mode) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, open64, name, flags, mode); - COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); - return REAL(open64)(name, flags, mode); -} -#define ESAN_MAYBE_INTERCEPT_OPEN64 INTERCEPT_FUNCTION(open64) -#else -#define ESAN_MAYBE_INTERCEPT_OPEN64 -#endif - -INTERCEPTOR(int, creat, const char *name, int mode) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, creat, name, mode); - COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); - return REAL(creat)(name, mode); -} - -#if SANITIZER_LINUX -INTERCEPTOR(int, creat64, const char *name, int mode) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, creat64, name, mode); - COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); - return REAL(creat64)(name, mode); -} -#define ESAN_MAYBE_INTERCEPT_CREAT64 INTERCEPT_FUNCTION(creat64) -#else -#define ESAN_MAYBE_INTERCEPT_CREAT64 -#endif - -INTERCEPTOR(int, unlink, char *path) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, unlink, path); - COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); - return REAL(unlink)(path); -} - -INTERCEPTOR(int, rmdir, char *path) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, rmdir, path); - COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); - return REAL(rmdir)(path); -} - -//===----------------------------------------------------------------------===// -// Signal-related interceptors -//===----------------------------------------------------------------------===// - -#if SANITIZER_LINUX || SANITIZER_FREEBSD -typedef void (*signal_handler_t)(int); -INTERCEPTOR(signal_handler_t, signal, int signum, signal_handler_t handler) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, signal, signum, handler); - signal_handler_t result; - if (!processSignal(signum, handler, &result)) - return result; - else - return REAL(signal)(signum, handler); -} -#define ESAN_MAYBE_INTERCEPT_SIGNAL INTERCEPT_FUNCTION(signal) -#else -#error Platform not supported -#define ESAN_MAYBE_INTERCEPT_SIGNAL -#endif - -#if SANITIZER_LINUX || SANITIZER_FREEBSD -DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act, - struct sigaction *oldact) -INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act, - struct sigaction *oldact) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, sigaction, signum, act, oldact); - if (!processSigaction(signum, act, oldact)) - return 0; - else - return REAL(sigaction)(signum, act, oldact); -} - -// This is required to properly use internal_sigaction. -namespace __sanitizer { -int real_sigaction(int signum, const void *act, void *oldact) { - if (REAL(sigaction) == nullptr) { - // With an instrumented allocator, this is called during interceptor init - // and we need a raw syscall solution. -#if SANITIZER_LINUX - return internal_sigaction_syscall(signum, act, oldact); -#else - return internal_sigaction(signum, act, oldact); -#endif - } - return REAL(sigaction)(signum, (const struct sigaction *)act, - (struct sigaction *)oldact); -} -} // namespace __sanitizer - -#define ESAN_MAYBE_INTERCEPT_SIGACTION INTERCEPT_FUNCTION(sigaction) -#else -#error Platform not supported -#define ESAN_MAYBE_INTERCEPT_SIGACTION -#endif - -#if SANITIZER_LINUX || SANITIZER_FREEBSD -INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set, - __sanitizer_sigset_t *oldset) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset); - int res = 0; - if (processSigprocmask(how, set, oldset)) - res = REAL(sigprocmask)(how, set, oldset); - if (!res && oldset) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); - return res; -} -#define ESAN_MAYBE_INTERCEPT_SIGPROCMASK INTERCEPT_FUNCTION(sigprocmask) -#else -#define ESAN_MAYBE_INTERCEPT_SIGPROCMASK -#endif - -#if !SANITIZER_WINDOWS -INTERCEPTOR(int, pthread_sigmask, int how, __sanitizer_sigset_t *set, - __sanitizer_sigset_t *oldset) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, pthread_sigmask, how, set, oldset); - int res = 0; - if (processSigprocmask(how, set, oldset)) - res = REAL(sigprocmask)(how, set, oldset); - if (!res && oldset) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); - return res; -} -#define ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK INTERCEPT_FUNCTION(pthread_sigmask) -#else -#define ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK -#endif - -//===----------------------------------------------------------------------===// -// Malloc interceptors -//===----------------------------------------------------------------------===// - -static const uptr early_alloc_buf_size = 4096; -static uptr allocated_bytes; -static char early_alloc_buf[early_alloc_buf_size]; - -static bool isInEarlyAllocBuf(const void *ptr) { - return ((uptr)ptr >= (uptr)early_alloc_buf && - ((uptr)ptr - (uptr)early_alloc_buf) < sizeof(early_alloc_buf)); -} - -static void *handleEarlyAlloc(uptr size) { - // If esan is initialized during an interceptor (which happens with some - // tcmalloc implementations that call pthread_mutex_lock), the call from - // dlsym to calloc will deadlock. - // dlsym may also call malloc before REAL(malloc) is retrieved from dlsym. - // We work around it by using a static buffer for the early malloc/calloc - // requests. - // This solution will also allow us to deliberately intercept malloc & family - // in the future (to perform tool actions on each allocation, without - // replacing the allocator), as it also solves the problem of intercepting - // calloc when it will itself be called before its REAL pointer is - // initialized. - // We do not handle multiple threads here. This only happens at process init - // time, and while it's possible for a shared library to create early threads - // that race here, we consider that to be a corner case extreme enough that - // it's not worth the effort to handle. - void *mem = (void *)&early_alloc_buf[allocated_bytes]; - allocated_bytes += size; - CHECK_LT(allocated_bytes, early_alloc_buf_size); - return mem; -} - -INTERCEPTOR(void*, calloc, uptr size, uptr n) { - if (EsanDuringInit && REAL(calloc) == nullptr) - return handleEarlyAlloc(size * n); - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, calloc, size, n); - void *res = REAL(calloc)(size, n); - // The memory is zeroed and thus is all written. - COMMON_INTERCEPTOR_WRITE_RANGE(nullptr, (uptr)res, size * n); - return res; -} - -INTERCEPTOR(void*, malloc, uptr size) { - if (EsanDuringInit && REAL(malloc) == nullptr) - return handleEarlyAlloc(size); - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, malloc, size); - return REAL(malloc)(size); -} - -INTERCEPTOR(void, free, void *p) { - void *ctx; - // There are only a few early allocation requests, so we simply skip the free. - if (isInEarlyAllocBuf(p)) - return; - COMMON_INTERCEPTOR_ENTER(ctx, free, p); - REAL(free)(p); -} - -namespace __esan { - -void initializeInterceptors() { - InitializeCommonInterceptors(); - - INTERCEPT_FUNCTION(strcpy); // NOLINT - INTERCEPT_FUNCTION(strncpy); - - INTERCEPT_FUNCTION(open); - ESAN_MAYBE_INTERCEPT_OPEN64; - INTERCEPT_FUNCTION(creat); - ESAN_MAYBE_INTERCEPT_CREAT64; - INTERCEPT_FUNCTION(unlink); - INTERCEPT_FUNCTION(rmdir); - - ESAN_MAYBE_INTERCEPT_SIGNAL; - ESAN_MAYBE_INTERCEPT_SIGACTION; - ESAN_MAYBE_INTERCEPT_SIGPROCMASK; - ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK; - - INTERCEPT_FUNCTION(calloc); - INTERCEPT_FUNCTION(malloc); - INTERCEPT_FUNCTION(free); - - // TODO(bruening): intercept routines that other sanitizers intercept that - // are not in the common pool or here yet, ideally by adding to the common - // pool. Examples include wcslen and bcopy. - - // TODO(bruening): there are many more libc routines that read or write data - // structures that no sanitizer is intercepting: sigaction, strtol, etc. -} - -} // namespace __esan Index: compiler-rt/lib/esan/esan_interface.cpp =================================================================== --- compiler-rt/lib/esan/esan_interface.cpp +++ /dev/null @@ -1,121 +0,0 @@ -//===-- esan_interface.cpp ------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -//===----------------------------------------------------------------------===// - -#include "esan_interface_internal.h" -#include "esan.h" -#include "sanitizer_common/sanitizer_internal_defs.h" - -using namespace __esan; // NOLINT - -void __esan_init(ToolType Tool, void *Ptr) { - if (Tool != __esan_which_tool) { - Printf("ERROR: tool mismatch: %d vs %d\n", Tool, __esan_which_tool); - Die(); - } - initializeLibrary(Tool); - processCompilationUnitInit(Ptr); -} - -void __esan_exit(void *Ptr) { - processCompilationUnitExit(Ptr); -} - -void __esan_aligned_load1(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 1, false); -} - -void __esan_aligned_load2(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, false); -} - -void __esan_aligned_load4(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, false); -} - -void __esan_aligned_load8(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, false); -} - -void __esan_aligned_load16(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, false); -} - -void __esan_aligned_store1(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 1, true); -} - -void __esan_aligned_store2(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, true); -} - -void __esan_aligned_store4(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, true); -} - -void __esan_aligned_store8(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, true); -} - -void __esan_aligned_store16(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, true); -} - -void __esan_unaligned_load2(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, false); -} - -void __esan_unaligned_load4(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, false); -} - -void __esan_unaligned_load8(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, false); -} - -void __esan_unaligned_load16(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, false); -} - -void __esan_unaligned_store2(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, true); -} - -void __esan_unaligned_store4(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, true); -} - -void __esan_unaligned_store8(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, true); -} - -void __esan_unaligned_store16(void *Addr) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, true); -} - -void __esan_unaligned_loadN(void *Addr, uptr Size) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, Size, false); -} - -void __esan_unaligned_storeN(void *Addr, uptr Size) { - processRangeAccess(GET_CALLER_PC(), (uptr)Addr, Size, true); -} - -// Public interface: -extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE void __esan_report() { - reportResults(); -} - -SANITIZER_INTERFACE_ATTRIBUTE unsigned int __esan_get_sample_count() { - return getSampleCount(); -} -} // extern "C" Index: compiler-rt/lib/esan/esan_interface_internal.h =================================================================== --- compiler-rt/lib/esan/esan_interface_internal.h +++ /dev/null @@ -1,82 +0,0 @@ -//===-- esan_interface_internal.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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Calls to the functions declared in this header will be inserted by -// the instrumentation module. -//===----------------------------------------------------------------------===// - -#ifndef ESAN_INTERFACE_INTERNAL_H -#define ESAN_INTERFACE_INTERNAL_H - -#include - -// This header should NOT include any other headers. -// All functions in this header are extern "C" and start with __esan_. - -using __sanitizer::uptr; -using __sanitizer::u32; - -extern "C" { - -// This should be kept consistent with LLVM's EfficiencySanitizerOptions. -// The value is passed as a 32-bit integer by the compiler. -typedef enum Type : u32 { - ESAN_None = 0, - ESAN_CacheFrag, - ESAN_WorkingSet, - ESAN_Max, -} ToolType; - -// To handle interceptors that invoke instrumented code prior to -// __esan_init() being called, the instrumentation module creates this -// global variable specifying the tool. -extern ToolType __esan_which_tool; - -// This function should be called at the very beginning of the process, -// before any instrumented code is executed and before any call to malloc. -SANITIZER_INTERFACE_ATTRIBUTE void __esan_init(ToolType Tool, void *Ptr); -SANITIZER_INTERFACE_ATTRIBUTE void __esan_exit(void *Ptr); - -// The instrumentation module will insert a call to one of these routines prior -// to each load and store instruction for which we do not have "fastpath" -// inlined instrumentation. These calls constitute the "slowpath" for our -// tools. We have separate routines for each type of memory access to enable -// targeted optimization. -SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load1(void *Addr); -SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load2(void *Addr); -SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load4(void *Addr); -SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load8(void *Addr); -SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load16(void *Addr); - -SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store1(void *Addr); -SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store2(void *Addr); -SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store4(void *Addr); -SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store8(void *Addr); -SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store16(void *Addr); - -SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load2(void *Addr); -SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load4(void *Addr); -SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load8(void *Addr); -SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load16(void *Addr); - -SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store2(void *Addr); -SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store4(void *Addr); -SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store8(void *Addr); -SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store16(void *Addr); - -// These cover unusually-sized accesses. -SANITIZER_INTERFACE_ATTRIBUTE -void __esan_unaligned_loadN(void *Addr, uptr Size); -SANITIZER_INTERFACE_ATTRIBUTE -void __esan_unaligned_storeN(void *Addr, uptr Size); - -} // extern "C" - -#endif // ESAN_INTERFACE_INTERNAL_H Index: compiler-rt/lib/esan/esan_linux.cpp =================================================================== --- compiler-rt/lib/esan/esan_linux.cpp +++ /dev/null @@ -1,82 +0,0 @@ -//===-- esan.cpp ----------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Linux-specific code for the Esan run-time. -//===----------------------------------------------------------------------===// - -#include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX - -#include "esan.h" -#include "esan_shadow.h" -#include "interception/interception.h" -#include "sanitizer_common/sanitizer_common.h" -#include -#include - -namespace __esan { - -void verifyAddressSpace() { -#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_MIPS64) - // The kernel determines its mmap base from the stack size limit. - // Our Linux 64-bit shadow mapping assumes the stack limit is less than a - // terabyte, which keeps the mmap region above 0x7e00'. - uptr StackLimit = GetStackSizeLimitInBytes(); - if (StackSizeIsUnlimited() || StackLimit > MaxStackSize) { - VReport(1, "The stack size limit is beyond the maximum supported.\n" - "Re-execing with a stack size below 1TB.\n"); - SetStackSizeLimitInBytes(MaxStackSize); - ReExec(); - } -#endif -} - -static bool liesWithinSingleAppRegion(uptr Start, SIZE_T Size) { - uptr AppStart, AppEnd; - for (int i = 0; getAppRegion(i, &AppStart, &AppEnd); ++i) { - if (Start >= AppStart && Start + Size - 1 <= AppEnd) { - return true; - } - } - return false; -} - -bool fixMmapAddr(void **Addr, SIZE_T Size, int Flags) { - if (*Addr) { - if (!liesWithinSingleAppRegion((uptr)*Addr, Size)) { - VPrintf(1, "mmap conflict: [%p-%p) is not in an app region\n", - *Addr, (uptr)*Addr + Size); - if (Flags & MAP_FIXED) { - errno = EINVAL; - return false; - } else { - *Addr = 0; - } - } - } - return true; -} - -uptr checkMmapResult(uptr Addr, SIZE_T Size) { - if ((void *)Addr == MAP_FAILED) - return Addr; - if (!liesWithinSingleAppRegion(Addr, Size)) { - // FIXME: attempt to dynamically add this as an app region if it - // fits our shadow criteria. - // We could also try to remap somewhere else. - Printf("ERROR: unsupported mapping at [%p-%p)\n", Addr, Addr+Size); - Die(); - } - return Addr; -} - -} // namespace __esan - -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX Index: compiler-rt/lib/esan/esan_shadow.h =================================================================== --- compiler-rt/lib/esan/esan_shadow.h +++ /dev/null @@ -1,291 +0,0 @@ -//===-- esan_shadow.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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Shadow memory mappings for the esan run-time. -//===----------------------------------------------------------------------===// - -#ifndef ESAN_SHADOW_H -#define ESAN_SHADOW_H - -#include "esan.h" -#include - -#if SANITIZER_WORDSIZE != 64 -#error Only 64-bit is supported -#endif - -namespace __esan { - -struct ApplicationRegion { - uptr Start; - uptr End; - bool ShadowMergedWithPrev; -}; - -#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && defined(__x86_64__) -// Linux x86_64 -// -// Application memory falls into these 5 regions (ignoring the corner case -// of PIE with a non-zero PT_LOAD base): -// -// [0x00000000'00000000, 0x00000100'00000000) non-PIE + heap -// [0x00005500'00000000, 0x00005700'00000000) PIE -// [0x00007e00'00000000, 0x00007fff'ff600000) libraries + stack, part 1 -// [0x00007fff'ff601000, 0x00008000'00000000) libraries + stack, part 2 -// [0xffffffff'ff600000, 0xffffffff'ff601000) vsyscall -// -// Although we can ignore the vsyscall for the most part as there are few data -// references there (other sanitizers ignore it), we enforce a gap inside the -// library region to distinguish the vsyscall's shadow, considering this gap to -// be an invalid app region. -// We disallow application memory outside of those 5 regions. -// Our regions assume that the stack rlimit is less than a terabyte (otherwise -// the Linux kernel's default mmap region drops below 0x7e00'), which we enforce -// at init time (we can support larger and unlimited sizes for shadow -// scaledowns, but it is difficult for 1:1 mappings). -// -// Our shadow memory is scaled from a 1:1 mapping and supports a scale -// specified at library initialization time that can be any power-of-2 -// scaledown (1x, 2x, 4x, 8x, 16x, etc.). -// -// We model our shadow memory after Umbra, a library used by the Dr. Memory -// tool: https://github.com/DynamoRIO/drmemory/blob/master/umbra/umbra_x64.c. -// We use Umbra's scheme as it was designed to support different -// offsets, it supports two different shadow mappings (which we may want to -// use for future tools), and it ensures that the shadow of a shadow will -// not overlap either shadow memory or application memory. -// -// This formula translates from application memory to shadow memory: -// -// shadow(app) = ((app & 0x00000fff'ffffffff) + offset) >> scale -// -// Where the offset for 1:1 is 0x00001300'00000000. For other scales, the -// offset is shifted left by the scale, except for scales of 1 and 2 where -// it must be tweaked in order to pass the double-shadow test -// (see the "shadow(shadow)" comments below): -// scale == 0: 0x00001300'000000000 -// scale == 1: 0x00002200'000000000 -// scale == 2: 0x00004400'000000000 -// scale >= 3: (0x00001300'000000000 << scale) -// -// Do not pass in the open-ended end value to the formula as it will fail. -// -// The resulting shadow memory regions for a 0 scaling are: -// -// [0x00001300'00000000, 0x00001400'00000000) -// [0x00001800'00000000, 0x00001a00'00000000) -// [0x00002100'00000000, 0x000022ff'ff600000) -// [0x000022ff'ff601000, 0x00002300'00000000) -// [0x000022ff'ff600000, 0x000022ff'ff601000] -// -// We also want to ensure that a wild access by the application into the shadow -// regions will not corrupt our own shadow memory. shadow(shadow) ends up -// disjoint from shadow(app): -// -// [0x00001600'00000000, 0x00001700'00000000) -// [0x00001b00'00000000, 0x00001d00'00000000) -// [0x00001400'00000000, 0x000015ff'ff600000] -// [0x000015ff'ff601000, 0x00001600'00000000] -// [0x000015ff'ff600000, 0x000015ff'ff601000] - -static const struct ApplicationRegion AppRegions[] = { - {0x0000000000000000ull, 0x0000010000000000u, false}, - {0x0000550000000000u, 0x0000570000000000u, false}, - // We make one shadow mapping to hold the shadow regions for all 3 of these - // app regions, as the mappings interleave, and the gap between the 3rd and - // 4th scales down below a page. - {0x00007e0000000000u, 0x00007fffff600000u, false}, - {0x00007fffff601000u, 0x0000800000000000u, true}, - {0xffffffffff600000u, 0xffffffffff601000u, true}, -}; - -#elif SANITIZER_LINUX && SANITIZER_MIPS64 - -// Application memory falls into these 3 regions -// -// [0x00000001'00000000, 0x00000002'00000000) non-PIE + heap -// [0x000000aa'00000000, 0x000000ab'00000000) PIE -// [0x000000ff'00000000, 0x000000ff'ffffffff) libraries + stack -// -// This formula translates from application memory to shadow memory: -// -// shadow(app) = ((app & 0x00000f'ffffffff) + offset) >> scale -// -// Where the offset for 1:1 is 0x000013'00000000. For other scales, the -// offset is shifted left by the scale, except for scales of 1 and 2 where -// it must be tweaked in order to pass the double-shadow test -// (see the "shadow(shadow)" comments below): -// scale == 0: 0x000013'00000000 -// scale == 1: 0x000022'00000000 -// scale == 2: 0x000044'00000000 -// scale >= 3: (0x000013'00000000 << scale) -// -// The resulting shadow memory regions for a 0 scaling are: -// -// [0x00000014'00000000, 0x00000015'00000000) -// [0x0000001d'00000000, 0x0000001e'00000000) -// [0x00000022'00000000, 0x00000022'ffffffff) -// -// We also want to ensure that a wild access by the application into the shadow -// regions will not corrupt our own shadow memory. shadow(shadow) ends up -// disjoint from shadow(app): -// -// [0x00000017'00000000, 0x00000018'00000000) -// [0x00000020'00000000, 0x00000021'00000000) -// [0x00000015'00000000, 0x00000015'ffffffff] - -static const struct ApplicationRegion AppRegions[] = { - {0x0100000000u, 0x0200000000u, false}, - {0xaa00000000u, 0xab00000000u, false}, - {0xff00000000u, 0xffffffffffu, false}, -}; - -#else -#error Platform not supported -#endif - -static const u32 NumAppRegions = sizeof(AppRegions)/sizeof(AppRegions[0]); - -// See the comment above: we do not currently support a stack size rlimit -// equal to or larger than 1TB. -static const uptr MaxStackSize = (1ULL << 40) - 4096; - -class ShadowMapping { -public: - - // The scale and offset vary by tool. - uptr Scale; - uptr Offset; - - // TODO(sagar.thakur): Try to hardcode the mask as done in the compiler - // instrumentation to reduce the runtime cost of appToShadow. - struct ShadowMemoryMask40 { - static const uptr Mask = 0x0000000fffffffffu; - }; - - struct ShadowMemoryMask47 { - static const uptr Mask = 0x00000fffffffffffu; - }; - - void initialize(uptr ShadowScale) { - - const uptr OffsetArray40[3] = { - 0x0000001300000000u, - 0x0000002200000000u, - 0x0000004400000000u, - }; - - const uptr OffsetArray47[3] = { - 0x0000130000000000u, - 0x0000220000000000u, - 0x0000440000000000u, - }; - - Scale = ShadowScale; - switch (VmaSize) { - case 40: { - if (Scale <= 2) - Offset = OffsetArray40[Scale]; - else - Offset = OffsetArray40[0] << Scale; - } - break; - case 47: { - if (Scale <= 2) - Offset = OffsetArray47[Scale]; - else - Offset = OffsetArray47[0] << Scale; - } - break; - default: { - Printf("ERROR: %d-bit virtual memory address size not supported\n", VmaSize); - Die(); - } - } - } -}; -extern ShadowMapping Mapping; - -static inline bool getAppRegion(u32 i, uptr *Start, uptr *End) { - if (i >= NumAppRegions) - return false; - *Start = AppRegions[i].Start; - *End = AppRegions[i].End; - return true; -} - -ALWAYS_INLINE -bool isAppMem(uptr Mem) { - for (u32 i = 0; i < NumAppRegions; ++i) { - if (Mem >= AppRegions[i].Start && Mem < AppRegions[i].End) - return true; - } - return false; -} - -template -uptr appToShadowImpl(uptr App) { - return (((App & Params::Mask) + Mapping.Offset) >> Mapping.Scale); -} - -ALWAYS_INLINE -uptr appToShadow(uptr App) { - switch (VmaSize) { - case 40: return appToShadowImpl(App); - case 47: return appToShadowImpl(App); - default: { - Printf("ERROR: %d-bit virtual memory address size not supported\n", VmaSize); - Die(); - } - } -} - -static inline bool getShadowRegion(u32 i, uptr *Start, uptr *End) { - if (i >= NumAppRegions) - return false; - u32 UnmergedShadowCount = 0; - u32 AppIdx; - for (AppIdx = 0; AppIdx < NumAppRegions; ++AppIdx) { - if (!AppRegions[AppIdx].ShadowMergedWithPrev) { - if (UnmergedShadowCount == i) - break; - UnmergedShadowCount++; - } - } - if (AppIdx >= NumAppRegions || UnmergedShadowCount != i) - return false; - *Start = appToShadow(AppRegions[AppIdx].Start); - // The formula fails for the end itself. - *End = appToShadow(AppRegions[AppIdx].End - 1) + 1; - // Merge with adjacent shadow regions: - for (++AppIdx; AppIdx < NumAppRegions; ++AppIdx) { - if (!AppRegions[AppIdx].ShadowMergedWithPrev) - break; - *Start = Min(*Start, appToShadow(AppRegions[AppIdx].Start)); - *End = Max(*End, appToShadow(AppRegions[AppIdx].End - 1) + 1); - } - return true; -} - -ALWAYS_INLINE -bool isShadowMem(uptr Mem) { - // We assume this is not used on any critical performance path and so there's - // no need to hardcode the mapping results. - for (uptr i = 0; i < NumAppRegions; ++i) { - if (Mem >= appToShadow(AppRegions[i].Start) && - Mem < appToShadow(AppRegions[i].End - 1) + 1) - return true; - } - return false; -} - -} // namespace __esan - -#endif /* ESAN_SHADOW_H */ Index: compiler-rt/lib/esan/esan_sideline.h =================================================================== --- compiler-rt/lib/esan/esan_sideline.h +++ /dev/null @@ -1,63 +0,0 @@ -//===-- esan_sideline.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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Esan sideline thread support. -//===----------------------------------------------------------------------===// - -#ifndef ESAN_SIDELINE_H -#define ESAN_SIDELINE_H - -#include "sanitizer_common/sanitizer_atomic.h" -#include "sanitizer_common/sanitizer_internal_defs.h" -#include "sanitizer_common/sanitizer_platform_limits_freebsd.h" -#include "sanitizer_common/sanitizer_platform_limits_posix.h" - -namespace __esan { - -typedef void (*SidelineFunc)(void *Arg); - -// Currently only one sideline thread is supported. -// It calls the SidelineFunc passed to launchThread once on each sample at the -// given frequency in real time (i.e., wall clock time). -class SidelineThread { -public: - // We cannot initialize any fields in the constructor as it will be called - // *after* launchThread for a static instance, as esan.module_ctor is called - // before static initializers. - SidelineThread() {} - ~SidelineThread() {} - - // To simplify declaration in sanitizer code where we want to avoid - // heap allocations, the constructor and destructor do nothing and - // launchThread and joinThread do the real work. - // They should each be called just once. - bool launchThread(SidelineFunc takeSample, void *Arg, u32 FreqMilliSec); - bool joinThread(); - - // Must be called from the sideline thread itself. - bool adjustTimer(u32 FreqMilliSec); - -private: - static int runSideline(void *Arg); - static void registerSignal(int SigNum); - static void handleSidelineSignal(int SigNum, __sanitizer_siginfo *SigInfo, - void *Ctx); - - char *Stack; - SidelineFunc sampleFunc; - void *FuncArg; - u32 Freq; - uptr SidelineId; - atomic_uintptr_t SidelineExit; -}; - -} // namespace __esan - -#endif // ESAN_SIDELINE_H Index: compiler-rt/lib/esan/esan_sideline_bsd.cpp =================================================================== --- compiler-rt/lib/esan/esan_sideline_bsd.cpp +++ /dev/null @@ -1,34 +0,0 @@ -//===-- esan_sideline_bsd.cpp -----------------------------------*- 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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Support for a separate or "sideline" tool thread on FreeBSD. -//===----------------------------------------------------------------------===// - -#include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_FREEBSD - -#include "esan_sideline.h" - -namespace __esan { - -static SidelineThread *TheThread; - -bool SidelineThread::launchThread(SidelineFunc takeSample, void *Arg, - u32 FreqMilliSec) { - return true; -} - -bool SidelineThread::joinThread() { - return true; -} - -} // namespace __esan - -#endif // SANITIZER_FREEBSD Index: compiler-rt/lib/esan/esan_sideline_linux.cpp =================================================================== --- compiler-rt/lib/esan/esan_sideline_linux.cpp +++ /dev/null @@ -1,177 +0,0 @@ -//===-- esan_sideline_linux.cpp ---------------------------------*- 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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Support for a separate or "sideline" tool thread on Linux. -//===----------------------------------------------------------------------===// - -#include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_LINUX - -#include "esan_sideline.h" -#include "sanitizer_common/sanitizer_atomic.h" -#include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_linux.h" -#include -#include -#include -#include -#include -#include -#include - -namespace __esan { - -static const int SigAltStackSize = 4*1024; -static const int SidelineStackSize = 4*1024; -static const uptr SidelineIdUninitialized = 1; - -// FIXME: we'll need some kind of TLS (can we trust that a pthread key will -// work in our non-POSIX thread?) to access our data in our signal handler -// with multiple sideline threads. For now we assume there is only one -// sideline thread and we use a dirty solution of a global var. -static SidelineThread *TheThread; - -// We aren't passing SA_NODEFER so the same signal is blocked while here. -void SidelineThread::handleSidelineSignal(int SigNum, - __sanitizer_siginfo *SigInfo, - void *Ctx) { - VPrintf(3, "Sideline signal %d\n", SigNum); - CHECK_EQ(SigNum, SIGALRM); - // See above about needing TLS to avoid this global var. - SidelineThread *Thread = TheThread; - if (atomic_load(&Thread->SidelineExit, memory_order_relaxed) != 0) - return; - Thread->sampleFunc(Thread->FuncArg); -} - -void SidelineThread::registerSignal(int SigNum) { - __sanitizer_sigaction SigAct; - internal_memset(&SigAct, 0, sizeof(SigAct)); - SigAct.sigaction = handleSidelineSignal; - // We do not pass SA_NODEFER as we want to block the same signal. - SigAct.sa_flags = SA_ONSTACK | SA_SIGINFO; - int Res = internal_sigaction(SigNum, &SigAct, nullptr); - CHECK_EQ(Res, 0); -} - -int SidelineThread::runSideline(void *Arg) { - VPrintf(1, "Sideline thread starting\n"); - SidelineThread *Thread = static_cast(Arg); - - // If the parent dies, we want to exit also. - internal_prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); - - // Set up a signal handler on an alternate stack for safety. - InternalMmapVector StackMap(SigAltStackSize); - stack_t SigAltStack; - SigAltStack.ss_sp = StackMap.data(); - SigAltStack.ss_size = SigAltStackSize; - SigAltStack.ss_flags = 0; - internal_sigaltstack(&SigAltStack, nullptr); - - // We inherit the signal mask from the app thread. In case - // we weren't created at init time, we ensure the mask is empty. - __sanitizer_sigset_t SigSet; - internal_sigfillset(&SigSet); - int Res = internal_sigprocmask(SIG_UNBLOCK, &SigSet, nullptr); - CHECK_EQ(Res, 0); - - registerSignal(SIGALRM); - - bool TimerSuccess = Thread->adjustTimer(Thread->Freq); - CHECK(TimerSuccess); - - // We loop, doing nothing but handling itimer signals. - while (atomic_load(&TheThread->SidelineExit, memory_order_relaxed) == 0) - sched_yield(); - - if (!Thread->adjustTimer(0)) - VPrintf(1, "Failed to disable timer\n"); - - VPrintf(1, "Sideline thread exiting\n"); - return 0; -} - -bool SidelineThread::launchThread(SidelineFunc takeSample, void *Arg, - u32 FreqMilliSec) { - // This can only be called once. However, we can't clear a field in - // the constructor and check for that here as the constructor for - // a static instance is called *after* our module_ctor and thus after - // this routine! Thus we rely on the TheThread check below. - CHECK(TheThread == nullptr); // Only one sideline thread is supported. - TheThread = this; - sampleFunc = takeSample; - FuncArg = Arg; - Freq = FreqMilliSec; - atomic_store(&SidelineExit, 0, memory_order_relaxed); - - // We do without a guard page. - Stack = static_cast(MmapOrDie(SidelineStackSize, "SidelineStack")); - // We need to handle the return value from internal_clone() not having been - // assigned yet (for our CHECK in adjustTimer()) so we ensure this has a - // sentinel value. - SidelineId = SidelineIdUninitialized; - // By omitting CLONE_THREAD, the child is in its own thread group and will not - // receive any of the application's signals. - SidelineId = internal_clone( - runSideline, Stack + SidelineStackSize, - CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED, - this, nullptr /* parent_tidptr */, - nullptr /* newtls */, nullptr /* child_tidptr */); - int ErrCode; - if (internal_iserror(SidelineId, &ErrCode)) { - Printf("FATAL: EfficiencySanitizer failed to spawn a thread (code %d).\n", - ErrCode); - Die(); - return false; // Not reached. - } - return true; -} - -bool SidelineThread::joinThread() { - VPrintf(1, "Joining sideline thread\n"); - bool Res = true; - atomic_store(&SidelineExit, 1, memory_order_relaxed); - while (true) { - uptr Status = internal_waitpid(SidelineId, nullptr, __WALL); - int ErrCode; - if (!internal_iserror(Status, &ErrCode)) - break; - if (ErrCode == EINTR) - continue; - VPrintf(1, "Failed to join sideline thread (errno %d)\n", ErrCode); - Res = false; - break; - } - UnmapOrDie(Stack, SidelineStackSize); - return Res; -} - -// Must be called from the sideline thread itself. -bool SidelineThread::adjustTimer(u32 FreqMilliSec) { - // The return value of internal_clone() may not have been assigned yet: - CHECK(internal_getpid() == SidelineId || - SidelineId == SidelineIdUninitialized); - Freq = FreqMilliSec; - struct itimerval TimerVal; - TimerVal.it_interval.tv_sec = (time_t) Freq / 1000; - TimerVal.it_interval.tv_usec = (time_t) (Freq % 1000) * 1000; - TimerVal.it_value.tv_sec = (time_t) Freq / 1000; - TimerVal.it_value.tv_usec = (time_t) (Freq % 1000) * 1000; - // As we're in a different thread group, we cannot use either - // ITIMER_PROF or ITIMER_VIRTUAL without taking up scheduled - // time ourselves: thus we must use real time. - int Res = setitimer(ITIMER_REAL, &TimerVal, nullptr); - return (Res == 0); -} - -} // namespace __esan - -#endif // SANITIZER_LINUX Index: compiler-rt/lib/esan/working_set.h =================================================================== --- compiler-rt/lib/esan/working_set.h +++ /dev/null @@ -1,39 +0,0 @@ -//===-- working_set.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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// Header for working-set-specific code. -//===----------------------------------------------------------------------===// - -#ifndef WORKING_SET_H -#define WORKING_SET_H - -#include "interception/interception.h" -#include "sanitizer_common/sanitizer_internal_defs.h" - -namespace __esan { - -void initializeWorkingSet(); -void initializeShadowWorkingSet(); -int finalizeWorkingSet(); -void reportWorkingSet(); -unsigned int getSampleCountWorkingSet(); -void processRangeAccessWorkingSet(uptr PC, uptr Addr, SIZE_T Size, - bool IsWrite); - -// Platform-dependent. -void registerMemoryFaultHandler(); -bool processWorkingSetSignal(int SigNum, void (*Handler)(int), - void (**Result)(int)); -bool processWorkingSetSigaction(int SigNum, const void *Act, void *OldAct); -bool processWorkingSetSigprocmask(int How, void *Set, void *OldSet); - -} // namespace __esan - -#endif // WORKING_SET_H Index: compiler-rt/lib/esan/working_set.cpp =================================================================== --- compiler-rt/lib/esan/working_set.cpp +++ /dev/null @@ -1,279 +0,0 @@ -//===-- working_set.cpp ---------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// This file contains working-set-specific code. -//===----------------------------------------------------------------------===// - -#include "working_set.h" -#include "esan.h" -#include "esan_circular_buffer.h" -#include "esan_flags.h" -#include "esan_shadow.h" -#include "esan_sideline.h" -#include "sanitizer_common/sanitizer_procmaps.h" - -// We shadow every cache line of app memory with one shadow byte. -// - The highest bit of each shadow byte indicates whether the corresponding -// cache line has ever been accessed. -// - The lowest bit of each shadow byte indicates whether the corresponding -// cache line was accessed since the last sample. -// - The other bits are used for working set snapshots at successively -// lower frequencies, each bit to the left from the lowest bit stepping -// down the frequency by 2 to the power of getFlags()->snapshot_step. -// Thus we have something like this: -// Bit 0: Since last sample -// Bit 1: Since last 2^2 samples -// Bit 2: Since last 2^4 samples -// Bit 3: ... -// Bit 7: Ever accessed. -// We live with races in accessing each shadow byte. -typedef unsigned char byte; - -namespace __esan { - -// Our shadow memory assumes that the line size is 64. -static const u32 CacheLineSize = 64; - -// See the shadow byte layout description above. -static const u32 TotalWorkingSetBitIdx = 7; -// We accumulate to the left until we hit this bit. -// We don't need to accumulate to the final bit as it's set on each ref -// by the compiler instrumentation. -static const u32 MaxAccumBitIdx = 6; -static const u32 CurWorkingSetBitIdx = 0; -static const byte ShadowAccessedVal = - (1 << TotalWorkingSetBitIdx) | (1 << CurWorkingSetBitIdx); - -static SidelineThread Thread; -// If we use real-time-based timer samples this won't overflow in any realistic -// scenario, but if we switch to some other unit (such as memory accesses) we -// may want to consider a 64-bit int. -static u32 SnapshotNum; - -// We store the wset size for each of 8 different sampling frequencies. -static const u32 NumFreq = 8; // One for each bit of our shadow bytes. -// We cannot use static objects as the global destructor is called -// prior to our finalize routine. -// These are each circular buffers, sized up front. -CircularBuffer SizePerFreq[NumFreq]; -// We cannot rely on static initializers (they may run too late) but -// we record the size here for clarity: -u32 CircularBufferSizes[NumFreq] = { - // These are each mmap-ed so our minimum is one page. - 32*1024, - 16*1024, - 8*1024, - 4*1024, - 4*1024, - 4*1024, - 4*1024, - 4*1024, -}; - -void processRangeAccessWorkingSet(uptr PC, uptr Addr, SIZE_T Size, - bool IsWrite) { - if (Size == 0) - return; - SIZE_T I = 0; - uptr LineSize = getFlags()->cache_line_size; - // As Addr+Size could overflow at the top of a 32-bit address space, - // we avoid the simpler formula that rounds the start and end. - SIZE_T NumLines = Size / LineSize + - // Add any extra at the start or end adding on an extra line: - (LineSize - 1 + Addr % LineSize + Size % LineSize) / LineSize; - byte *Shadow = (byte *)appToShadow(Addr); - // Write shadow bytes until we're word-aligned. - while (I < NumLines && (uptr)Shadow % 4 != 0) { - if ((*Shadow & ShadowAccessedVal) != ShadowAccessedVal) - *Shadow |= ShadowAccessedVal; - ++Shadow; - ++I; - } - // Write whole shadow words at a time. - // Using a word-stride loop improves the runtime of a microbenchmark of - // memset calls by 10%. - u32 WordValue = ShadowAccessedVal | ShadowAccessedVal << 8 | - ShadowAccessedVal << 16 | ShadowAccessedVal << 24; - while (I + 4 <= NumLines) { - if ((*(u32*)Shadow & WordValue) != WordValue) - *(u32*)Shadow |= WordValue; - Shadow += 4; - I += 4; - } - // Write any trailing shadow bytes. - while (I < NumLines) { - if ((*Shadow & ShadowAccessedVal) != ShadowAccessedVal) - *Shadow |= ShadowAccessedVal; - ++Shadow; - ++I; - } -} - -// This routine will word-align ShadowStart and ShadowEnd prior to scanning. -// It does *not* clear for BitIdx==TotalWorkingSetBitIdx, as that top bit -// measures the access during the entire execution and should never be cleared. -static u32 countAndClearShadowValues(u32 BitIdx, uptr ShadowStart, - uptr ShadowEnd) { - u32 WorkingSetSize = 0; - u32 ByteValue = 0x1 << BitIdx; - u32 WordValue = ByteValue | ByteValue << 8 | ByteValue << 16 | - ByteValue << 24; - // Get word aligned start. - ShadowStart = RoundDownTo(ShadowStart, sizeof(u32)); - bool Accum = getFlags()->record_snapshots && BitIdx < MaxAccumBitIdx; - // Do not clear the bit that measures access during the entire execution. - bool Clear = BitIdx < TotalWorkingSetBitIdx; - for (u32 *Ptr = (u32 *)ShadowStart; Ptr < (u32 *)ShadowEnd; ++Ptr) { - if ((*Ptr & WordValue) != 0) { - byte *BytePtr = (byte *)Ptr; - for (u32 j = 0; j < sizeof(u32); ++j) { - if (BytePtr[j] & ByteValue) { - ++WorkingSetSize; - if (Accum) { - // Accumulate to the lower-frequency bit to the left. - BytePtr[j] |= (ByteValue << 1); - } - } - } - if (Clear) { - // Clear this bit from every shadow byte. - *Ptr &= ~WordValue; - } - } - } - return WorkingSetSize; -} - -// Scan shadow memory to calculate the number of cache lines being accessed, -// i.e., the number of non-zero bits indexed by BitIdx in each shadow byte. -// We also clear the lowest bits (most recent working set snapshot). -// We do *not* clear for BitIdx==TotalWorkingSetBitIdx, as that top bit -// measures the access during the entire execution and should never be cleared. -static u32 computeWorkingSizeAndReset(u32 BitIdx) { - u32 WorkingSetSize = 0; - MemoryMappingLayout MemIter(true/*cache*/); - MemoryMappedSegment Segment; - while (MemIter.Next(&Segment)) { - VPrintf(4, "%s: considering %p-%p app=%d shadow=%d prot=%u\n", __FUNCTION__, - Segment.start, Segment.end, Segment.protection, - isAppMem(Segment.start), isShadowMem(Segment.start)); - if (isShadowMem(Segment.start) && Segment.IsWritable()) { - VPrintf(3, "%s: walking %p-%p\n", __FUNCTION__, Segment.start, - Segment.end); - WorkingSetSize += - countAndClearShadowValues(BitIdx, Segment.start, Segment.end); - } - } - return WorkingSetSize; -} - -// This is invoked from a signal handler but in a sideline thread doing nothing -// else so it is a little less fragile than a typical signal handler. -static void takeSample(void *Arg) { - u32 BitIdx = CurWorkingSetBitIdx; - u32 Freq = 1; - ++SnapshotNum; // Simpler to skip 0 whose mod matches everything. - while (BitIdx <= MaxAccumBitIdx && (SnapshotNum % Freq) == 0) { - u32 NumLines = computeWorkingSizeAndReset(BitIdx); - VReport(1, "%s: snapshot #%5d bit %d freq %4d: %8u\n", SanitizerToolName, - SnapshotNum, BitIdx, Freq, NumLines); - SizePerFreq[BitIdx].push_back(NumLines); - Freq = Freq << getFlags()->snapshot_step; - BitIdx++; - } -} - -unsigned int getSampleCountWorkingSet() -{ - return SnapshotNum; -} - -// Initialization that must be done before any instrumented code is executed. -void initializeShadowWorkingSet() { - CHECK(getFlags()->cache_line_size == CacheLineSize); - registerMemoryFaultHandler(); -} - -void initializeWorkingSet() { - if (getFlags()->record_snapshots) { - for (u32 i = 0; i < NumFreq; ++i) - SizePerFreq[i].initialize(CircularBufferSizes[i]); - Thread.launchThread(takeSample, nullptr, getFlags()->sample_freq); - } -} - -static u32 getPeriodForPrinting(u32 MilliSec, const char *&Unit) { - if (MilliSec > 600000) { - Unit = "min"; - return MilliSec / 60000; - } else if (MilliSec > 10000) { - Unit = "sec"; - return MilliSec / 1000; - } else { - Unit = "ms"; - return MilliSec; - } -} - -static u32 getSizeForPrinting(u32 NumOfCachelines, const char *&Unit) { - // We need a constant to avoid software divide support: - static const u32 KilobyteCachelines = (0x1 << 10) / CacheLineSize; - static const u32 MegabyteCachelines = KilobyteCachelines << 10; - - if (NumOfCachelines > 10 * MegabyteCachelines) { - Unit = "MB"; - return NumOfCachelines / MegabyteCachelines; - } else if (NumOfCachelines > 10 * KilobyteCachelines) { - Unit = "KB"; - return NumOfCachelines / KilobyteCachelines; - } else { - Unit = "Bytes"; - return NumOfCachelines * CacheLineSize; - } -} - -void reportWorkingSet() { - const char *Unit; - if (getFlags()->record_snapshots) { - u32 Freq = 1; - Report(" Total number of samples: %u\n", SnapshotNum); - for (u32 i = 0; i < NumFreq; ++i) { - u32 Time = getPeriodForPrinting(getFlags()->sample_freq*Freq, Unit); - Report(" Samples array #%d at period %u %s\n", i, Time, Unit); - // FIXME: report whether we wrapped around and thus whether we - // have data on the whole run or just the last N samples. - for (u32 j = 0; j < SizePerFreq[i].size(); ++j) { - u32 Size = getSizeForPrinting(SizePerFreq[i][j], Unit); - Report("#%4d: %8u %s (%9u cache lines)\n", j, Size, Unit, - SizePerFreq[i][j]); - } - Freq = Freq << getFlags()->snapshot_step; - } - } - - // Get the working set size for the entire execution. - u32 NumOfCachelines = computeWorkingSizeAndReset(TotalWorkingSetBitIdx); - u32 Size = getSizeForPrinting(NumOfCachelines, Unit); - Report(" %s: the total working set size: %u %s (%u cache lines)\n", - SanitizerToolName, Size, Unit, NumOfCachelines); -} - -int finalizeWorkingSet() { - if (getFlags()->record_snapshots) - Thread.joinThread(); - reportWorkingSet(); - if (getFlags()->record_snapshots) { - for (u32 i = 0; i < NumFreq; ++i) - SizePerFreq[i].free(); - } - return 0; -} - -} // namespace __esan Index: compiler-rt/lib/esan/working_set_posix.cpp =================================================================== --- compiler-rt/lib/esan/working_set_posix.cpp +++ /dev/null @@ -1,133 +0,0 @@ -//===-- working_set_posix.cpp -----------------------------------*- 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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners. -// -// POSIX-specific working set tool code. -//===----------------------------------------------------------------------===// - -#include "working_set.h" -#include "esan_flags.h" -#include "esan_shadow.h" -#include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_linux.h" -#include -#include - -namespace __esan { - -// We only support regular POSIX threads with a single signal handler -// for the whole process == thread group. -// Thus we only need to store one app signal handler. -// FIXME: Store and use any alternate stack and signal flags set by -// the app. For now we just call the app handler from our handler. -static __sanitizer_sigaction AppSigAct; - -bool processWorkingSetSignal(int SigNum, void (*Handler)(int), - void (**Result)(int)) { - VPrintf(2, "%s: %d\n", __FUNCTION__, SigNum); - if (SigNum == SIGSEGV) { - *Result = AppSigAct.handler; - AppSigAct.sigaction = (decltype(AppSigAct.sigaction))Handler; - return false; // Skip real call. - } - return true; -} - -bool processWorkingSetSigaction(int SigNum, const void *ActVoid, - void *OldActVoid) { - VPrintf(2, "%s: %d\n", __FUNCTION__, SigNum); - if (SigNum == SIGSEGV) { - const struct sigaction *Act = (const struct sigaction *) ActVoid; - struct sigaction *OldAct = (struct sigaction *) OldActVoid; - if (OldAct) - internal_memcpy(OldAct, &AppSigAct, sizeof(OldAct)); - if (Act) - internal_memcpy(&AppSigAct, Act, sizeof(AppSigAct)); - return false; // Skip real call. - } - return true; -} - -bool processWorkingSetSigprocmask(int How, void *Set, void *OldSet) { - VPrintf(2, "%s\n", __FUNCTION__); - // All we need to do is ensure that SIGSEGV is not blocked. - // FIXME: we are not fully transparent as we do not pretend that - // SIGSEGV is still blocked on app queries: that would require - // per-thread mask tracking. - if (Set && (How == SIG_BLOCK || How == SIG_SETMASK)) { - if (internal_sigismember((__sanitizer_sigset_t *)Set, SIGSEGV)) { - VPrintf(1, "%s: removing SIGSEGV from the blocked set\n", __FUNCTION__); - internal_sigdelset((__sanitizer_sigset_t *)Set, SIGSEGV); - } - } - return true; -} - -static void reinstateDefaultHandler(int SigNum) { - __sanitizer_sigaction SigAct; - internal_memset(&SigAct, 0, sizeof(SigAct)); - SigAct.sigaction = (decltype(SigAct.sigaction))SIG_DFL; - int Res = internal_sigaction(SigNum, &SigAct, nullptr); - CHECK(Res == 0); - VPrintf(1, "Unregistered for %d handler\n", SigNum); -} - -// If this is a shadow fault, we handle it here; otherwise, we pass it to the -// app to handle it just as the app would do without our tool in place. -static void handleMemoryFault(int SigNum, __sanitizer_siginfo *Info, - void *Ctx) { - if (SigNum == SIGSEGV) { - // We rely on si_addr being filled in (thus we do not support old kernels). - siginfo_t *SigInfo = (siginfo_t *)Info; - uptr Addr = (uptr)SigInfo->si_addr; - if (isShadowMem(Addr)) { - VPrintf(3, "Shadow fault @%p\n", Addr); - uptr PageSize = GetPageSizeCached(); - int Res = internal_mprotect((void *)RoundDownTo(Addr, PageSize), - PageSize, PROT_READ|PROT_WRITE); - CHECK(Res == 0); - } else if (AppSigAct.sigaction) { - // FIXME: For simplicity we ignore app options including its signal stack - // (we just use ours) and all the delivery flags. - AppSigAct.sigaction(SigNum, Info, Ctx); - } else { - // Crash instead of spinning with infinite faults. - reinstateDefaultHandler(SigNum); - } - } else - UNREACHABLE("signal not registered"); -} - -void registerMemoryFaultHandler() { - // We do not use an alternate signal stack, as doing so would require - // setting it up for each app thread. - // FIXME: This could result in problems with emulating the app's signal - // handling if the app relies on an alternate stack for SIGSEGV. - - // We require that SIGSEGV is not blocked. We use a sigprocmask - // interceptor to ensure that in the future. Here we ensure it for - // the current thread. We assume there are no other threads at this - // point during initialization, or that at least they do not block - // SIGSEGV. - __sanitizer_sigset_t SigSet; - internal_sigemptyset(&SigSet); - internal_sigprocmask(SIG_BLOCK, &SigSet, nullptr); - - __sanitizer_sigaction SigAct; - internal_memset(&SigAct, 0, sizeof(SigAct)); - SigAct.sigaction = handleMemoryFault; - // We want to handle nested signals b/c we need to handle a - // shadow fault in an app signal handler. - SigAct.sa_flags = SA_SIGINFO | SA_NODEFER; - int Res = internal_sigaction(SIGSEGV, &SigAct, &AppSigAct); - CHECK(Res == 0); - VPrintf(1, "Registered for SIGSEGV handler\n"); -} - -} // namespace __esan Index: compiler-rt/lib/sanitizer_common/sanitizer_common.h =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -238,7 +238,6 @@ char **GetEnviron(); void PrintCmdline(); bool StackSizeIsUnlimited(); -uptr GetStackSizeLimitInBytes(); void SetStackSizeLimitInBytes(uptr limit); bool AddressSpaceIsUnlimited(); void SetAddressSpaceUnlimited(); Index: compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h +++ compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h @@ -422,7 +422,6 @@ namespace __asan { using namespace __sanitizer; } // NOLINT namespace __dsan { using namespace __sanitizer; } // NOLINT namespace __dfsan { using namespace __sanitizer; } // NOLINT -namespace __esan { using namespace __sanitizer; } // NOLINT namespace __lsan { using namespace __sanitizer; } // NOLINT namespace __msan { using namespace __sanitizer; } // NOLINT namespace __hwasan { using namespace __sanitizer; } // NOLINT Index: compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -116,10 +116,6 @@ return (stack_size == RLIM_INFINITY); } -uptr GetStackSizeLimitInBytes() { - return (uptr)getlim(RLIMIT_STACK); -} - void SetStackSizeLimitInBytes(uptr limit) { setlim(RLIMIT_STACK, (rlim_t)limit); CHECK(!StackSizeIsUnlimited()); Index: compiler-rt/test/esan/CMakeLists.txt =================================================================== --- compiler-rt/test/esan/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -set(ESAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) -if(NOT COMPILER_RT_STANDALONE_BUILD) - list(APPEND ESAN_TEST_DEPS esan) -endif() - -set(ESAN_TESTSUITES) - -set(ESAN_TEST_ARCH ${ESAN_SUPPORTED_ARCH}) - -set(ESAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) - -foreach(arch ${ESAN_TEST_ARCH}) - set(ESAN_TEST_TARGET_ARCH ${arch}) - string(TOLOWER "-${arch}" ESAN_TEST_CONFIG_SUFFIX) - get_target_flags_for_arch(${arch} ESAN_TEST_TARGET_CFLAGS) - string(REPLACE ";" " " ESAN_TEST_TARGET_CFLAGS "${ESAN_TEST_TARGET_CFLAGS}") - - string(TOUPPER ${arch} ARCH_UPPER_CASE) - set(CONFIG_NAME ${ARCH_UPPER_CASE}Config) - - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg) - list(APPEND ESAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) -endforeach() - -# TODO(bruening): add Unit/ tests as well - -add_lit_testsuite(check-esan "Running EfficiencySanitizer tests" - ${ESAN_TESTSUITES} - DEPENDS ${ESAN_TEST_DEPS}) -set_target_properties(check-esan PROPERTIES FOLDER "Compiler-RT Misc") Index: compiler-rt/test/esan/TestCases/large-stack-linux.c =================================================================== --- compiler-rt/test/esan/TestCases/large-stack-linux.c +++ /dev/null @@ -1,76 +0,0 @@ -// RUN: %clang_esan_wset -O0 %s -o %t 2>&1 -// RUN: %env_esan_opts="verbosity=1 record_snapshots=0" %run %t %t 2>&1 | FileCheck %s -// Stucks at init and no clone feature equivalent. -// UNSUPPORTED: freebsd - -#include -#include -#include -#include -#include -#include -#include - -static void testChildStackLimit(rlim_t StackLimit, char *ToRun) { - int Res; - struct rlimit Limit; - Limit.rlim_cur = RLIM_INFINITY; - Limit.rlim_max = RLIM_INFINITY; - Res = setrlimit(RLIMIT_STACK, &Limit); - if (Res != 0) { - // Probably our environment had a large limit and we ourselves got - // re-execed and can no longer raise our limit. - // We have to bail and emulate the regular test. - // We'd prefer to have branches in our FileCheck output to ensure the - // initial program was re-execed but this is the best we can do for now. - fprintf(stderr, "in esan::initializeLibrary\n"); - fprintf(stderr, "==1234==The stack size limit is beyond the maximum supported.\n"); - fprintf(stderr, "Re-execing with a stack size below 1TB.\n"); - fprintf(stderr, "in esan::initializeLibrary\n"); - fprintf(stderr, "done\n"); - fprintf(stderr, "in esan::finalizeLibrary\n"); - return; - } - - pid_t Child = fork(); - assert(Child >= 0); - if (Child > 0) { - pid_t WaitRes = waitpid(Child, NULL, 0); - assert(WaitRes == Child); - } else { - char *Args[2]; - Args[0] = ToRun; - Args[1] = NULL; - Res = execv(ToRun, Args); - assert(0); // Should not be reached. - } -} - -int main(int argc, char *argv[]) { - // The path to the program to exec must be passed in the first time. - if (argc == 2) { - fprintf(stderr, "Testing child with infinite stack\n"); - testChildStackLimit(RLIM_INFINITY, argv[1]); - fprintf(stderr, "Testing child with 1TB stack\n"); - testChildStackLimit(1ULL << 40, argv[1]); - } - fprintf(stderr, "done\n"); - // CHECK: in esan::initializeLibrary - // CHECK: Testing child with infinite stack - // CHECK-NEXT: in esan::initializeLibrary - // CHECK-NEXT: =={{[0-9:]+}}==The stack size limit is beyond the maximum supported. - // CHECK-NEXT: Re-execing with a stack size below 1TB. - // CHECK-NEXT: in esan::initializeLibrary - // CHECK: done - // CHECK: in esan::finalizeLibrary - // CHECK: Testing child with 1TB stack - // CHECK-NEXT: in esan::initializeLibrary - // CHECK-NEXT: =={{[0-9:]+}}==The stack size limit is beyond the maximum supported. - // CHECK-NEXT: Re-execing with a stack size below 1TB. - // CHECK-NEXT: in esan::initializeLibrary - // CHECK: done - // CHECK-NEXT: in esan::finalizeLibrary - // CHECK: done - // CHECK-NEXT: in esan::finalizeLibrary - return 0; -} Index: compiler-rt/test/esan/TestCases/libc-intercept.c =================================================================== --- compiler-rt/test/esan/TestCases/libc-intercept.c +++ /dev/null @@ -1,20 +0,0 @@ -// RUN: %clang_esan_frag -O0 %s -o %t 2>&1 -// RUN: %env_esan_opts=verbosity=3 %run %t 2>&1 | FileCheck %s - -#include - -int main(int argc, char **argv) { - char Buf[2048]; - const char Str[] = "TestStringOfParticularLength"; // 29 chars. - strcpy(Buf, Str); - strncpy(Buf, Str, 17); - return strncmp(Buf, Str, 17); - // CHECK: in esan::initializeLibrary - // CHECK: in esan::processRangeAccess {{.*}} 29 - // CHECK: in esan::processRangeAccess {{.*}} 29 - // CHECK: in esan::processRangeAccess {{.*}} 17 - // CHECK: in esan::processRangeAccess {{.*}} 17 - // CHECK: in esan::processRangeAccess {{.*}} 17 - // CHECK: in esan::processRangeAccess {{.*}} 17 - // CHECK: in esan::finalizeLibrary -} Index: compiler-rt/test/esan/TestCases/mmap-shadow-conflict.c =================================================================== --- compiler-rt/test/esan/TestCases/mmap-shadow-conflict.c +++ /dev/null @@ -1,44 +0,0 @@ -// RUN: %clang_esan_frag -O0 %s -o %t 2>&1 -// RUN: %env_esan_opts=verbosity=1 %run %t 2>&1 | FileCheck --check-prefix=%arch --check-prefix=CHECK %s - -#include -#include -#include - -int main(int argc, char **argv) { -#if defined(__mips64) - void *Map = mmap((void *)0x0000001600000000ULL, 0x1000, PROT_READ, - MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); -#else - void *Map = mmap((void *)0x0000016000000000ULL, 0x1000, PROT_READ, - MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); -#endif - if (Map == (void *)-1) - fprintf(stderr, "map failed\n"); - else - fprintf(stderr, "mapped %p\n", Map); -#if defined(__mips64) - Map = mmap((void *)0x0000001600000000ULL, 0x1000, PROT_READ, - MAP_ANON|MAP_PRIVATE, -1, 0); -#else - Map = mmap((void *)0x0000016000000000ULL, 0x1000, PROT_READ, - MAP_ANON|MAP_PRIVATE, -1, 0); -#endif - fprintf(stderr, "mapped %p\n", Map); - // CHECK: in esan::initializeLibrary - // (There can be a re-exec for stack limit here.) - // x86_64: Shadow scale=2 offset=0x440000000000 - // x86_64-NEXT: Shadow #0: [110000000000-114000000000) (256GB) - // x86_64-NEXT: Shadow #1: [124000000000-12c000000000) (512GB) - // x86_64-NEXT: Shadow #2: [148000000000-150000000000) (512GB) - // mips64: Shadow scale=2 offset=0x4400000000 - // mips64-NEXT: Shadow #0: [1140000000-1180000000) (1GB) - // mips64-NEXT: Shadow #1: [1380000000-13c0000000) (1GB) - // mips64-NEXT: Shadow #2: [14c0000000-1500000000) (1GB) - // CHECK-NEXT: mmap conflict: {{.*}} - // CHECK-NEXT: map failed - // CHECK-NEXT: mmap conflict: {{.*}} - // CHECK-NEXT: mapped {{.*}} - // CHECK-NEXT: in esan::finalizeLibrary - return 0; -} Index: compiler-rt/test/esan/TestCases/struct-simple.cpp =================================================================== --- compiler-rt/test/esan/TestCases/struct-simple.cpp +++ /dev/null @@ -1,204 +0,0 @@ -// RUN: %clang_esan_frag -O0 %s -DPART1 -mllvm -esan-aux-field-info=0 -c -o %t-part1.o 2>&1 -// RUN: %clang_esan_frag -O0 %s -DPART2 -c -o %t-part2.o 2>&1 -// RUN: %clang_esan_frag -O0 %s -DMAIN -c -o %t-main.o 2>&1 -// RUN: %clang_esan_frag -O0 %t-part1.o %t-part2.o %t-main.o -o %t 2>&1 -// RUN: %env_esan_opts=verbosity=2 %run %t 2>&1 | FileCheck %s - -// We generate two different object files from this file with different -// macros, and then link them together. We do this to test how we handle -// separate compilation with multiple compilation units. - -#include - -extern "C" { - void part1(); - void part2(); -} - -//===-- compilation unit part1 without main function ----------------------===// - -#ifdef PART1 -struct A { - int x; - int y; -}; - -struct B { - float m; - double n; -}; - -union U { - float f; - double d; -}; - -// Same struct in both main and part1. -struct S { - int s1; - int s2; -}; - -// Different structs with the same name in main and part1. -struct D { - int d1; - int d2; - struct { - int x; - int y; - int z; - } ds[10]; -}; - -void part1() -{ - struct A a; - struct B b; - union U u; - struct S s; - struct D d; - for (int i = 0; i < (1 << 11); i++) - a.x = 0; - a.y = 1; - b.m = 2.0; - for (int i = 0; i < (1 << 21); i++) { - b.n = 3.0; - d.ds[3].y = 0; - } - u.f = 0.0; - u.d = 1.0; - s.s1 = 0; - d.d1 = 0; -} -#endif // PART1 - -//===-- compilation unit part2 without main function ----------------------===// -#ifdef PART2 -// No struct in this part. -void part2() -{ - // do nothing -} -#endif // PART2 - -//===-- compilation unit with main function -------------------------------===// - -#ifdef MAIN -class C { -public: - struct { - int x; - int y; - } cs; - union { - float f; - double d; - } cu; - char c[10]; -}; - -// Same struct in both main and part1. -struct S { - int s1; - int s2; -}; - -// Different structs with the same name in main and part1. -struct D { - int d1; - int d2; - int d3; -}; - -int main(int argc, char **argv) { - // CHECK: in esan::initializeLibrary - // CHECK: in esan::initializeCacheFrag - // CHECK-NEXT: in esan::processCompilationUnitInit - // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 6 class(es)/struct(s) - // CHECK-NEXT: Register struct.A$2$11$11: 2 fields - // CHECK-NEXT: Register struct.B$2$3$2: 2 fields - // CHECK-NEXT: Register union.U$1$3: 1 fields - // CHECK-NEXT: Register struct.S$2$11$11: 2 fields - // CHECK-NEXT: Register struct.D$3$14$11$11: 3 fields - // CHECK-NEXT: Register struct.anon$3$11$11$11: 3 fields - // CHECK-NEXT: in esan::processCompilationUnitInit - // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 0 class(es)/struct(s) - // CHECK-NEXT: in esan::processCompilationUnitInit - // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 5 class(es)/struct(s) - // CHECK-NEXT: Register class.C$3$14$13$13: 3 fields - // CHECK-NEXT: Register struct.anon$2$11$11: 2 fields - // CHECK-NEXT: Register union.anon$1$3: 1 fields - // CHECK-NEXT: Duplicated struct.S$2$11$11: 2 fields - // CHECK-NEXT: Register struct.D$3$11$11$11: 3 fields - struct C c[2]; - struct S s; - struct D d; - c[0].cs.x = 0; - c[1].cs.y = 1; - c[0].cu.f = 0.0; - c[1].cu.d = 1.0; - c[0].c[2] = 0; - s.s1 = 0; - d.d1 = 0; - d.d2 = 0; - part1(); - part2(); - return 0; - // CHECK: in esan::finalizeLibrary - // CHECK-NEXT: in esan::finalizeCacheFrag - // CHECK-NEXT: in esan::processCompilationUnitExit - // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 5 class(es)/struct(s) - // CHECK-NEXT: Unregister class.C$3$14$13$13: 3 fields - // CHECK-NEXT: {{.*}} class C - // CHECK-NEXT: {{.*}} size = 32, count = 5, ratio = 3, array access = 5 - // CHECK-NEXT: {{.*}} # 0: offset = 0, size = 8, count = 2, type = %struct.anon = type { i32, i32 } - // CHECK-NEXT: {{.*}} # 1: offset = 8, size = 8, count = 2, type = %union.anon = type { double } - // CHECK-NEXT: {{.*}} # 2: offset = 16, size = 10, count = 1, type = [10 x i8] - // CHECK-NEXT: Unregister struct.anon$2$11$11: 2 fields - // CHECK-NEXT: {{.*}} struct anon - // CHECK-NEXT: {{.*}} size = 8, count = 2, ratio = 1, array access = 0 - // CHECK-NEXT: {{.*}} # 0: offset = 0, size = 4, count = 1, type = i32 - // CHECK-NEXT: {{.*}} # 1: offset = 4, size = 4, count = 1, type = i32 - // CHECK-NEXT: Unregister union.anon$1$3: 1 fields - // CHECK-NEXT: Unregister struct.S$2$11$11: 2 fields - // CHECK-NEXT: {{.*}} struct S - // CHECK-NEXT: {{.*}} size = 8, count = 2, ratio = 2, array access = 0 - // CHECK-NEXT: {{.*}} # 0: count = 2 - // CHECK-NEXT: {{.*}} # 1: count = 0 - // CHECK-NEXT: Unregister struct.D$3$11$11$11: 3 fields - // CHECK-NEXT: {{.*}} struct D - // CHECK-NEXT: {{.*}} size = 12, count = 2, ratio = 2, array access = 0 - // CHECK-NEXT: {{.*}} # 0: offset = 0, size = 4, count = 1, type = i32 - // CHECK-NEXT: {{.*}} # 1: offset = 4, size = 4, count = 1, type = i32 - // CHECK-NEXT: {{.*}} # 2: offset = 8, size = 4, count = 0, type = i32 - // CHECK-NEXT: in esan::processCompilationUnitExit - // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 0 class(es)/struct(s) - // CHECK-NEXT: in esan::processCompilationUnitExit - // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 6 class(es)/struct(s) - // CHECK-NEXT: Unregister struct.A$2$11$11: 2 fields - // CHECK-NEXT: {{.*}} struct A - // CHECK-NEXT: {{.*}} size = 8, count = 2049, ratio = 2048, array access = 0 - // CHECK-NEXT: {{.*}} # 0: count = 2048 - // CHECK-NEXT: {{.*}} # 1: count = 1 - // CHECK-NEXT: Unregister struct.B$2$3$2: 2 fields - // CHECK-NEXT: {{.*}} struct B - // CHECK-NEXT: {{.*}} size = 16, count = 2097153, ratio = 2097152, array access = 0 - // CHECK-NEXT: {{.*}} # 0: count = 1 - // CHECK-NEXT: {{.*}} # 1: count = 2097152 - // CHECK-NEXT: Unregister union.U$1$3: 1 fields - // CHECK-NEXT: Duplicated struct.S$2$11$11: 2 fields - // CHECK-NEXT: Unregister struct.D$3$14$11$11: 3 fields - // CHECK-NEXT: {{.*}} struct D - // CHECK-NEXT: {{.*}} size = 128, count = 2097153, ratio = 2097153, array access = 0 - // CHECK-NEXT: {{.*}} # 0: count = 1 - // CHECK-NEXT: {{.*}} # 1: count = 0 - // CHECK-NEXT: {{.*}} # 2: count = 2097152 - // CHECK-NEXT: Unregister struct.anon$3$11$11$11: 3 fields - // CHECK-NEXT: {{.*}} struct anon - // CHECK-NEXT: {{.*}} size = 12, count = 2097152, ratio = 4194304, array access = 2097152 - // CHECK-NEXT: {{.*}} # 0: count = 0 - // CHECK-NEXT: {{.*}} # 1: count = 2097152 - // CHECK-NEXT: {{.*}} # 2: count = 0 - // CHECK-NEXT: {{.*}}EfficiencySanitizer: total struct field access count = 6293518 -} -#endif // MAIN Index: compiler-rt/test/esan/TestCases/verbose-simple.c =================================================================== --- compiler-rt/test/esan/TestCases/verbose-simple.c +++ /dev/null @@ -1,18 +0,0 @@ -// RUN: %clang_esan_frag -O0 %s -o %t 2>&1 -// RUN: %env_esan_opts="verbosity=1 log_exe_name=1" %run %t 2>&1 | FileCheck --check-prefix=%arch --check-prefix=CHECK %s - -int main(int argc, char **argv) { - // CHECK: in esan::initializeLibrary - // (There can be a re-exec for stack limit here.) - // x86_64: Shadow scale=2 offset=0x440000000000 - // x86_64-NEXT: Shadow #0: [110000000000-114000000000) (256GB) - // x86_64-NEXT: Shadow #1: [124000000000-12c000000000) (512GB) - // x86_64-NEXT: Shadow #2: [148000000000-150000000000) (512GB) - // mips64: Shadow scale=2 offset=0x4400000000 - // mips64-NEXT: Shadow #0: [1140000000-1180000000) (1GB) - // mips64-NEXT: Shadow #1: [1380000000-13c0000000) (1GB) - // mips64-NEXT: Shadow #2: [14c0000000-1500000000) (1GB) - // CHECK: in esan::finalizeLibrary - // CHECK: ==verbose-simple{{.*}}EfficiencySanitizer: total struct field access count = 0 - return 0; -} Index: compiler-rt/test/esan/TestCases/workingset-early-fault.c =================================================================== --- compiler-rt/test/esan/TestCases/workingset-early-fault.c +++ /dev/null @@ -1,35 +0,0 @@ -// Test shadow faults during esan initialization as well as -// faults during dlsym's calloc during interceptor init. -// -// RUN: %clang_esan_wset %s -o %t -// RUN: %run %t 2>&1 | FileCheck %s -// Stucks at init and no clone feature equivalent. -// UNSUPPORTED: freebsd - -#include -#include -#include - -// Our goal is to emulate an instrumented allocator, whose calloc -// invoked from dlsym will trigger shadow faults, to test an -// early shadow fault during esan interceptor init. -// We do this by replacing calloc: -void *calloc(size_t size, size_t n) { - // Unfortunately we can't print anything to make the test - // ensure we got here b/c the sanitizer interceptors can't - // handle that during interceptor init. - - // Ensure we trigger a shadow write fault: - int x[16]; - x[0] = size; - // Now just emulate calloc. - void *res = malloc(size*n); - memset(res, 0, size*n); - return res; -} - -int main(int argc, char **argv) { - printf("all done\n"); - return 0; -} -// CHECK: all done Index: compiler-rt/test/esan/TestCases/workingset-memset.cpp =================================================================== --- compiler-rt/test/esan/TestCases/workingset-memset.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// RUN: %clang_esan_wset -O0 %s -o %t 2>&1 -// RUN: %run %t 2>&1 | FileCheck %s -// Stucks at init and no clone feature equivalent. -// UNSUPPORTED: freebsd - -#include -#include -#include -#include -#include - -int main(int argc, char **argv) { - const int size = 128*1024*1024; - char *p = (char *)mmap(0, size, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, -1, 0); - // Test the slowpath at different cache line boundaries. - for (int i = 0; i < 630; i++) - memset((char *)p + 63*i, i, 63*i); - munmap(p, size); - return 0; - // CHECK: {{.*}} EfficiencySanitizer: the total working set size: 77 KB (12{{[0-9]+}} cache lines) -} Index: compiler-rt/test/esan/TestCases/workingset-midreport.cpp =================================================================== --- compiler-rt/test/esan/TestCases/workingset-midreport.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// RUN: %clang_esan_wset -O0 %s -o %t 2>&1 -// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN - -// RUN: %clang -O0 %s -o %t 2>&1 -// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NO-ESAN - -// FIXME: Re-enable once PR33590 is fixed. -// UNSUPPORTED: x86_64 -// Stucks at init and no clone feature equivalent. -// UNSUPPORTED: freebsd - -#include -#include -#include -#include -#include -#include - -const int size = 0x1 << 25; // 523288 cache lines -const int iters = 6; - -int main(int argc, char **argv) { - char *buf = (char *)mmap(0, size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - // To avoid flakiness stemming from whether the sideline thread - // is scheduled enough on a loaded test machine, we coordinate - // with esan itself: - if (__esan_get_sample_count) { - while (__esan_get_sample_count() < 4) { - for (int i = 0; i < size; ++i) - buf[i] = i; - sched_yield(); - } - } - // Ensure a non-esan build works without ifdefs: - if (__esan_report) { - // We should get 2 roughly identical reports: - __esan_report(); - } - munmap(buf, size); - fprintf(stderr, "all done\n"); - // CHECK-NO-ESAN: all done - // We only check for a few samples here to reduce the chance of flakiness: - // CHECK-ESAN: =={{[0-9]+}}== Total number of samples: {{[0-9]+}} - // CHECK-ESAN-NEXT: =={{[0-9]+}}== Samples array #0 at period 20 ms - // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines) - // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 1: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines) - // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 2: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines) - // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 3: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines) - // CHECK-ESAN: =={{[0-9]+}}== Samples array #1 at period 80 ms - // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines) - // CHECK-ESAN: =={{[0-9]+}}== Samples array #2 at period 320 ms - // CHECK-ESAN: =={{[0-9]+}}== Samples array #3 at period 1280 ms - // CHECK-ESAN: =={{[0-9]+}}== Samples array #4 at period 5120 ms - // CHECK-ESAN: =={{[0-9]+}}== Samples array #5 at period 20 sec - // CHECK-ESAN: =={{[0-9]+}}== Samples array #6 at period 81 sec - // CHECK-ESAN: =={{[0-9]+}}== Samples array #7 at period 327 sec - // CHECK-ESAN: {{.*}} EfficiencySanitizer: the total working set size: 32 MB (5242{{[0-9][0-9]}} cache lines) - // CHECK-ESAN-NEXT: all done - // CHECK-ESAN-NEXT: =={{[0-9]+}}== Total number of samples: {{[0-9]+}} - // CHECK-ESAN-NEXT: =={{[0-9]+}}== Samples array #0 at period 20 ms - // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines) - // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 1: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines) - // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 2: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines) - // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 3: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines) - // CHECK-ESAN: =={{[0-9]+}}== Samples array #1 at period 80 ms - // CHECK-ESAN-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines) - // CHECK-ESAN: =={{[0-9]+}}== Samples array #2 at period 320 ms - // CHECK-ESAN: =={{[0-9]+}}== Samples array #3 at period 1280 ms - // CHECK-ESAN: =={{[0-9]+}}== Samples array #4 at period 5120 ms - // CHECK-ESAN: =={{[0-9]+}}== Samples array #5 at period 20 sec - // CHECK-ESAN: =={{[0-9]+}}== Samples array #6 at period 81 sec - // CHECK-ESAN: =={{[0-9]+}}== Samples array #7 at period 327 sec - // CHECK-ESAN: {{.*}} EfficiencySanitizer: the total working set size: 32 MB (5242{{[0-9][0-9]}} cache lines) - return 0; -} Index: compiler-rt/test/esan/TestCases/workingset-samples.cpp =================================================================== --- compiler-rt/test/esan/TestCases/workingset-samples.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// RUN: %clang_esan_wset -O0 %s -o %t 2>&1 -// RUN: %run %t 2>&1 | FileCheck %s - -// FIXME: Re-enable once PR33590 is fixed. -// UNSUPPORTED: x86_64 -// Stucks at init and no clone feature equivalent. -// UNSUPPORTED: freebsd - -#include -#include -#include -#include -#include - -const int size = 0x1 << 25; // 523288 cache lines - -int main(int argc, char **argv) { - char *buf = (char *)mmap(0, size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - // To avoid flakiness stemming from whether the sideline thread - // is scheduled enough on a loaded test machine, we coordinate - // with esan itself: - if (__esan_get_sample_count) { - while (__esan_get_sample_count() < 4) { - for (int i = 0; i < size; ++i) - buf[i] = i; - sched_yield(); - } - } - munmap(buf, size); - // We only check for a few samples here to reduce the chance of flakiness. - // CHECK: =={{[0-9]+}}== Total number of samples: {{[0-9]+}} - // CHECK-NEXT: =={{[0-9]+}}== Samples array #0 at period 20 ms - // CHECK-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines) - // CHECK-NEXT: =={{[0-9]+}}==# 1: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines) - // CHECK-NEXT: =={{[0-9]+}}==# 2: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines) - // CHECK-NEXT: =={{[0-9]+}}==# 3: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines) - // CHECK: =={{[0-9]+}}== Samples array #1 at period 80 ms - // CHECK-NEXT: =={{[0-9]+}}==# 0: {{[ 0-9]+}} {{KB|MB|Bytes}} ({{[ 0-9]+}} cache lines) - // CHECK: =={{[0-9]+}}== Samples array #2 at period 320 ms - // CHECK: =={{[0-9]+}}== Samples array #3 at period 1280 ms - // CHECK: =={{[0-9]+}}== Samples array #4 at period 5120 ms - // CHECK: =={{[0-9]+}}== Samples array #5 at period 20 sec - // CHECK: =={{[0-9]+}}== Samples array #6 at period 81 sec - // CHECK: =={{[0-9]+}}== Samples array #7 at period 327 sec - // CHECK: {{.*}} EfficiencySanitizer: the total working set size: 32 MB (5242{{[0-9][0-9]}} cache lines) - return 0; -} Index: compiler-rt/test/esan/TestCases/workingset-signal-posix.cpp =================================================================== --- compiler-rt/test/esan/TestCases/workingset-signal-posix.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// RUN: %clang_esan_wset -O0 %s -o %t 2>&1 -// RUN: %run %t 2>&1 | FileCheck %s -// Stucks at init and no clone feature equivalent. -// UNSUPPORTED: freebsd - -#include -#include -#include -#include -#include -#include - -sigjmp_buf mark; - -static void SignalHandler(int Sig) { - if (Sig == SIGSEGV) { - fprintf(stderr, "Handling SIGSEGV for signal\n"); - siglongjmp(mark, 1); - } - exit(1); -} - -static void SigactionHandler(int Sig, siginfo_t *Info, void *Ctx) { - if (Sig == SIGSEGV) { - fprintf(stderr, "Handling SIGSEGV for sigaction\n"); - siglongjmp(mark, 1); - } - exit(1); -} - -int main(int argc, char **argv) { - __sighandler_t Prior = signal(SIGSEGV, SignalHandler); - assert(Prior == SIG_DFL); - if (sigsetjmp(mark, 1) == 0) - *((volatile int *)(ssize_t)argc) = 42; // Raise SIGSEGV - fprintf(stderr, "Past longjmp for signal\n"); - - Prior = signal(SIGSEGV, SIG_DFL); - assert(Prior == SignalHandler); - - struct sigaction SigAct; - SigAct.sa_sigaction = SigactionHandler; - int Res = sigfillset(&SigAct.sa_mask); - assert(Res == 0); - SigAct.sa_flags = SA_SIGINFO; - Res = sigaction(SIGSEGV, &SigAct, NULL); - assert(Res == 0); - - if (sigsetjmp(mark, 1) == 0) - *((volatile int *)(ssize_t)argc) = 42; // Raise SIGSEGV - fprintf(stderr, "Past longjmp for sigaction\n"); - - Res = sigaction(SIGSEGV, NULL, &SigAct); - assert(Res == 0); - assert(SigAct.sa_sigaction == SigactionHandler); - - // Test blocking SIGSEGV and raising a shadow fault. - sigset_t Set; - sigemptyset(&Set); - sigaddset(&Set, SIGSEGV); - Res = sigprocmask(SIG_BLOCK, &Set, NULL); - // Make a large enough mapping that its start point will be before any - // prior library-region shadow access. - char *buf = (char *)mmap(0, 640*1024, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - buf[0] = 4; - munmap(buf, 640*1024); - fprintf(stderr, "Past blocked-SIGSEGV shadow fault\n"); - - return 0; -} -// CHECK: Handling SIGSEGV for signal -// CHECK-NEXT: Past longjmp for signal -// CHECK-NEXT: Handling SIGSEGV for sigaction -// CHECK-NEXT: Past longjmp for sigaction -// CHECK-NEXT: Past blocked-SIGSEGV shadow fault -// CHECK: {{.*}} EfficiencySanitizer: the total working set size: {{[0-9]+}} Bytes ({{[0-9][0-9]}} cache lines) Index: compiler-rt/test/esan/TestCases/workingset-simple.cpp =================================================================== --- compiler-rt/test/esan/TestCases/workingset-simple.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// RUN: %clang_esan_wset -O0 %s -o %t 2>&1 -// RUN: %run %t 2>&1 | FileCheck %s - -// FIXME: Re-enable once PR33590 is fixed. -// UNSUPPORTED: x86_64 -// Stucks at init and no clone feature equivalent. -// UNSUPPORTED: freebsd - -#include -#include -#include -#include - -const int size = 0x1 << 25; // 523288 cache lines -const int line_size = 64; - -int main(int argc, char **argv) { - char *bufA = (char *)malloc(sizeof(char) * line_size); - char bufB[64]; - char *bufC = (char *)mmap(0, size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - bufA[0] = 0; - // This additional access to the same line should not increase the line - // count: but it's difficult to make a non-flaky test that measures the - // lines down to the ones digit so right now we're not really testing that. - // If we add a heap-only mode we may be able to be more precise. - bufA[1] = 0; - bufB[33] = 1; - for (int i = 0; i < size; i += line_size) - bufC[i] = 0; - free(bufA); - munmap(bufC, 0x4000); - // CHECK: {{.*}} EfficiencySanitizer: the total working set size: 32 MB (524{{[0-9][0-9][0-9]}} cache lines) - return 0; -} Index: compiler-rt/test/esan/Unit/circular_buffer.cpp =================================================================== --- compiler-rt/test/esan/Unit/circular_buffer.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// RUN: %clangxx_unit -O0 %s -o %t 2>&1 -// RUN: %env_esan_opts="record_snapshots=0" %run %t 2>&1 | FileCheck %s - -#include "esan/esan_circular_buffer.h" -#include "sanitizer_common/sanitizer_placement_new.h" -#include -#include - -static const int TestBufCapacity = 4; - -// The buffer should have a capacity of TestBufCapacity. -void testBuffer(__esan::CircularBuffer *Buf) { - assert(Buf->size() == 0); - assert(Buf->empty()); - - Buf->push_back(1); - assert(Buf->back() == 1); - assert((*Buf)[0] == 1); - assert(Buf->size() == 1); - assert(!Buf->empty()); - - Buf->push_back(2); - Buf->push_back(3); - Buf->push_back(4); - Buf->push_back(5); - assert((*Buf)[0] == 2); - assert(Buf->size() == 4); - - Buf->pop_back(); - assert((*Buf)[0] == 2); - assert(Buf->size() == 3); - - Buf->pop_back(); - Buf->pop_back(); - assert((*Buf)[0] == 2); - assert(Buf->size() == 1); - assert(!Buf->empty()); - - Buf->pop_back(); - assert(Buf->empty()); -} - -int main() -{ - // Test initialize/free. - __esan::CircularBuffer GlobalBuf; - GlobalBuf.initialize(TestBufCapacity); - testBuffer(&GlobalBuf); - GlobalBuf.free(); - - // Test constructor/free. - __esan::CircularBuffer *LocalBuf; - static char placeholder[sizeof(*LocalBuf)]; - LocalBuf = new(placeholder) __esan::CircularBuffer(TestBufCapacity); - testBuffer(LocalBuf); - LocalBuf->free(); - - fprintf(stderr, "All checks passed.\n"); - // CHECK: All checks passed. - return 0; -} Index: compiler-rt/test/esan/Unit/hashtable.cpp =================================================================== --- compiler-rt/test/esan/Unit/hashtable.cpp +++ /dev/null @@ -1,179 +0,0 @@ -// RUN: %clangxx_unit -esan-instrument-loads-and-stores=0 -O0 %s -o %t 2>&1 -// RUN: %env_esan_opts="record_snapshots=0" %run %t 2>&1 | FileCheck %s - -#include "esan/esan_hashtable.h" -#include -#include -#include -#include - -class MyData { - public: - MyData(const char *Str) : RefCount(0) { Buf = strdup(Str); } - ~MyData() { - fprintf(stderr, " Destructor: %s.\n", Buf); - free(Buf); - } - bool operator==(MyData &Cmp) { return strcmp(Buf, Cmp.Buf) == 0; } - operator size_t() const { - size_t Res = 0; - for (int i = 0; i < strlen(Buf); ++i) - Res ^= Buf[i]; - return Res; - } - char *Buf; - int RefCount; -}; - -// We use a smart pointer wrapper to free the payload on hashtable removal. -struct MyDataPayload { - MyDataPayload() : Data(nullptr) {} - explicit MyDataPayload(MyData *Data) : Data(Data) { ++Data->RefCount; } - ~MyDataPayload() { - if (Data && --Data->RefCount == 0) { - fprintf(stderr, "Deleting %s.\n", Data->Buf); - delete Data; - } - } - MyDataPayload(const MyDataPayload &Copy) { - Data = Copy.Data; - ++Data->RefCount; - } - MyDataPayload & operator=(const MyDataPayload &Copy) { - if (this != &Copy) { - this->~MyDataPayload(); - Data = Copy.Data; - ++Data->RefCount; - } - return *this; - } - bool operator==(MyDataPayload &Cmp) { return *Data == *Cmp.Data; } - operator size_t() const { return (size_t)*Data; } - MyData *Data; -}; - -int main() -{ - __esan::HashTable IntTable; - assert(IntTable.size() == 0); - - // Test iteration on an empty table. - int Count = 0; - for (auto Iter = IntTable.begin(); Iter != IntTable.end(); - ++Iter, ++Count) { - // Empty. - } - assert(Count == 0); - - bool Added = IntTable.add(4, 42); - assert(Added); - assert(!IntTable.add(4, 42)); - assert(IntTable.size() == 1); - int Value; - bool Found = IntTable.lookup(4, Value); - assert(Found && Value == 42); - - // Test iterator. - IntTable.lock(); - for (auto Iter = IntTable.begin(); Iter != IntTable.end(); - ++Iter, ++Count) { - assert((*Iter).Key == 4); - assert((*Iter).Data == 42); - } - IntTable.unlock(); - assert(Count == 1); - assert(Count == IntTable.size()); - assert(!IntTable.remove(5)); - assert(IntTable.remove(4)); - - // Test a more complex payload. - __esan::HashTable DataTable(4); - MyDataPayload NewData(new MyData("mystring")); - Added = DataTable.add(4, NewData); - assert(Added); - MyDataPayload FoundData; - Found = DataTable.lookup(4, FoundData); - assert(Found && strcmp(FoundData.Data->Buf, "mystring") == 0); - assert(!DataTable.remove(5)); - assert(DataTable.remove(4)); - // Test resize. - for (int i = 0; i < 4; ++i) { - MyDataPayload MoreData(new MyData("delete-at-end")); - Added = DataTable.add(i+1, MoreData); - assert(Added); - assert(!DataTable.add(i+1, MoreData)); - } - for (int i = 0; i < 4; ++i) { - Found = DataTable.lookup(i+1, FoundData); - assert(Found && strcmp(FoundData.Data->Buf, "delete-at-end") == 0); - } - DataTable.lock(); - Count = 0; - for (auto Iter = DataTable.begin(); Iter != DataTable.end(); - ++Iter, ++Count) { - int Key = (*Iter).Key; - FoundData = (*Iter).Data; - assert(Key >= 1 && Key <= 4); - assert(strcmp(FoundData.Data->Buf, "delete-at-end") == 0); - } - DataTable.unlock(); - assert(Count == 4); - assert(Count == DataTable.size()); - - // Ensure the iterator supports a range-based for loop. - DataTable.lock(); - Count = 0; - for (auto Pair : DataTable) { - assert(Pair.Key >= 1 && Pair.Key <= 4); - assert(strcmp(Pair.Data.Data->Buf, "delete-at-end") == 0); - ++Count; - } - DataTable.unlock(); - assert(Count == 4); - assert(Count == DataTable.size()); - - // Test payload freeing via smart pointer wrapper. - __esan::HashTable DataKeyTable; - MyDataPayload DataA(new MyData("string AB")); - DataKeyTable.lock(); - Added = DataKeyTable.add(DataA, DataA); - assert(Added); - Found = DataKeyTable.lookup(DataA, FoundData); - assert(Found && strcmp(FoundData.Data->Buf, "string AB") == 0); - MyDataPayload DataB(new MyData("string AB")); - Added = DataKeyTable.add(DataB, DataB); - assert(!Added); - DataKeyTable.remove(DataB); // Should free the DataA payload. - DataKeyTable.unlock(); - - // Test custom functors. - struct CustomHash { - size_t operator()(int Key) const { return Key % 4; } - }; - struct CustomEqual { - bool operator()(int Key1, int Key2) const { return Key1 %4 == Key2 % 4; } - }; - __esan::HashTable ModTable; - Added = ModTable.add(2, 42); - assert(Added); - Added = ModTable.add(6, 42); - assert(!Added); - - fprintf(stderr, "All checks passed.\n"); - return 0; -} -// CHECK: Deleting mystring. -// CHECK-NEXT: Destructor: mystring. -// CHECK-NEXT: All checks passed. -// CHECK-NEXT: Deleting string AB. -// CHECK-NEXT: Destructor: string AB. -// CHECK-NEXT: Deleting string AB. -// CHECK-NEXT: Destructor: string AB. -// CHECK-NEXT: Deleting delete-at-end. -// CHECK-NEXT: Destructor: delete-at-end. -// CHECK-NEXT: Deleting delete-at-end. -// CHECK-NEXT: Destructor: delete-at-end. -// CHECK-NEXT: Deleting delete-at-end. -// CHECK-NEXT: Destructor: delete-at-end. -// CHECK-NEXT: Deleting delete-at-end. -// CHECK-NEXT: Destructor: delete-at-end. Index: compiler-rt/test/esan/lit.cfg =================================================================== --- compiler-rt/test/esan/lit.cfg +++ /dev/null @@ -1,43 +0,0 @@ -# -*- Python -*- - -import os - -# Setup config name. -config.name = 'EfficiencySanitizer' + config.name_suffix - -# Setup source root. -config.test_source_root = os.path.dirname(__file__) - -# Setup default compiler flags used with -fsanitize=efficiency option. -base_cflags = ([config.target_cflags] + config.debug_info_flags) -base_cxxflags = config.cxx_mode_flags + base_cflags - -frag_cflags = (["-fsanitize=efficiency-cache-frag"] + base_cflags) -wset_cflags = (["-fsanitize=efficiency-working-set"] + base_cflags) -esan_incdir = config.test_source_root + "/../../lib" -unit_cxxflags = (["-I%s" % esan_incdir, "-std=c++11", - # We need to link with the esan runtime. - # Tests should pass %env_esan_opts="record_snapshots=0". - "-fsanitize=efficiency-working-set"] + base_cxxflags) - -def build_invocation(compile_flags): - return " " + " ".join([config.clang] + compile_flags) + " " - -config.substitutions.append( ("%clang ", - build_invocation(base_cflags)) ) -config.substitutions.append( ("%clang_esan_frag ", - build_invocation(frag_cflags)) ) -config.substitutions.append( ("%clang_esan_wset ", - build_invocation(wset_cflags)) ) -config.substitutions.append( ("%clangxx_unit", - build_invocation(unit_cxxflags)) ) - -default_esan_opts = '' -config.substitutions.append(('%env_esan_opts=', - 'env ESAN_OPTIONS=' + default_esan_opts)) - -# Default test suffixes. -config.suffixes = ['.c', '.cpp'] - -if config.host_os not in ['Linux', 'FreeBSD'] or config.target_arch not in ['x86_64', 'mips64'] : - config.unsupported = True Index: compiler-rt/test/esan/lit.site.cfg.in =================================================================== --- compiler-rt/test/esan/lit.site.cfg.in +++ /dev/null @@ -1,14 +0,0 @@ -## Autogenerated by LLVM/Clang configuration. -# Do not edit! - -# Tool-specific config options. -config.name_suffix = "@ESAN_TEST_CONFIG_SUFFIX@" -config.esan_lit_source_dir = "@ESAN_LIT_SOURCE_DIR@" -config.target_cflags = "@ESAN_TEST_TARGET_CFLAGS@" -config.target_arch = "@ESAN_TEST_TARGET_ARCH@" - -# Load common config for all compiler-rt lit tests. -lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") - -# Load tool-specific config that would do the real work. -lit_config.load_config(config, "@ESAN_LIT_SOURCE_DIR@/lit.cfg") Index: llvm/include/llvm/InitializePasses.h =================================================================== --- llvm/include/llvm/InitializePasses.h +++ llvm/include/llvm/InitializePasses.h @@ -134,7 +134,6 @@ void initializeEarlyMachineLICMPass(PassRegistry&); void initializeEarlyTailDuplicatePass(PassRegistry&); void initializeEdgeBundlesPass(PassRegistry&); -void initializeEfficiencySanitizerPass(PassRegistry&); void initializeEliminateAvailableExternallyLegacyPassPass(PassRegistry&); void initializeEntryExitInstrumenterPass(PassRegistry&); void initializeExpandISelPseudosPass(PassRegistry&); Index: llvm/include/llvm/Transforms/Instrumentation.h =================================================================== --- llvm/include/llvm/Transforms/Instrumentation.h +++ llvm/include/llvm/Transforms/Instrumentation.h @@ -160,21 +160,6 @@ const std::vector &ABIListFiles = std::vector(), void *(*getArgTLS)() = nullptr, void *(*getRetValTLS)() = nullptr); -// Options for EfficiencySanitizer sub-tools. -struct EfficiencySanitizerOptions { - enum Type { - ESAN_None = 0, - ESAN_CacheFrag, - ESAN_WorkingSet, - } ToolType = ESAN_None; - - EfficiencySanitizerOptions() = default; -}; - -// Insert EfficiencySanitizer instrumentation. -ModulePass *createEfficiencySanitizerPass( - const EfficiencySanitizerOptions &Options = EfficiencySanitizerOptions()); - // Options for sanitizer coverage instrumentation. struct SanitizerCoverageOptions { enum Type { Index: llvm/lib/Transforms/Instrumentation/CMakeLists.txt =================================================================== --- llvm/lib/Transforms/Instrumentation/CMakeLists.txt +++ llvm/lib/Transforms/Instrumentation/CMakeLists.txt @@ -14,7 +14,6 @@ PGOMemOPSizeOpt.cpp SanitizerCoverage.cpp ThreadSanitizer.cpp - EfficiencySanitizer.cpp HWAddressSanitizer.cpp ADDITIONAL_HEADER_DIRS Index: llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp +++ /dev/null @@ -1,892 +0,0 @@ -//===-- EfficiencySanitizer.cpp - performance tuner -----------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// This file is a part of EfficiencySanitizer, a family of performance tuners -// that detects multiple performance issues via separate sub-tools. -// -// The instrumentation phase is straightforward: -// - Take action on every memory access: either inlined instrumentation, -// or Inserted calls to our run-time library. -// - Optimizations may apply to avoid instrumenting some of the accesses. -// - Turn mem{set,cpy,move} instrinsics into library calls. -// The rest is handled by the run-time library. -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Analysis/TargetLibraryInfo.h" -#include "llvm/Transforms/Utils/Local.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Type.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/Instrumentation.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/Transforms/Utils/ModuleUtils.h" - -using namespace llvm; - -#define DEBUG_TYPE "esan" - -// The tool type must be just one of these ClTool* options, as the tools -// cannot be combined due to shadow memory constraints. -static cl::opt - ClToolCacheFrag("esan-cache-frag", cl::init(false), - cl::desc("Detect data cache fragmentation"), cl::Hidden); -static cl::opt - ClToolWorkingSet("esan-working-set", cl::init(false), - cl::desc("Measure the working set size"), cl::Hidden); -// Each new tool will get its own opt flag here. -// These are converted to EfficiencySanitizerOptions for use -// in the code. - -static cl::opt ClInstrumentLoadsAndStores( - "esan-instrument-loads-and-stores", cl::init(true), - cl::desc("Instrument loads and stores"), cl::Hidden); -static cl::opt ClInstrumentMemIntrinsics( - "esan-instrument-memintrinsics", cl::init(true), - cl::desc("Instrument memintrinsics (memset/memcpy/memmove)"), cl::Hidden); -static cl::opt ClInstrumentFastpath( - "esan-instrument-fastpath", cl::init(true), - cl::desc("Instrument fastpath"), cl::Hidden); -static cl::opt ClAuxFieldInfo( - "esan-aux-field-info", cl::init(true), - cl::desc("Generate binary with auxiliary struct field information"), - cl::Hidden); - -// Experiments show that the performance difference can be 2x or more, -// and accuracy loss is typically negligible, so we turn this on by default. -static cl::opt ClAssumeIntraCacheLine( - "esan-assume-intra-cache-line", cl::init(true), - cl::desc("Assume each memory access touches just one cache line, for " - "better performance but with a potential loss of accuracy."), - cl::Hidden); - -STATISTIC(NumInstrumentedLoads, "Number of instrumented loads"); -STATISTIC(NumInstrumentedStores, "Number of instrumented stores"); -STATISTIC(NumFastpaths, "Number of instrumented fastpaths"); -STATISTIC(NumAccessesWithIrregularSize, - "Number of accesses with a size outside our targeted callout sizes"); -STATISTIC(NumIgnoredStructs, "Number of ignored structs"); -STATISTIC(NumIgnoredGEPs, "Number of ignored GEP instructions"); -STATISTIC(NumInstrumentedGEPs, "Number of instrumented GEP instructions"); -STATISTIC(NumAssumedIntraCacheLine, - "Number of accesses assumed to be intra-cache-line"); - -static const uint64_t EsanCtorAndDtorPriority = 0; -static const char *const EsanModuleCtorName = "esan.module_ctor"; -static const char *const EsanModuleDtorName = "esan.module_dtor"; -static const char *const EsanInitName = "__esan_init"; -static const char *const EsanExitName = "__esan_exit"; - -// We need to specify the tool to the runtime earlier than -// the ctor is called in some cases, so we set a global variable. -static const char *const EsanWhichToolName = "__esan_which_tool"; - -// We must keep these Shadow* constants consistent with the esan runtime. -// FIXME: Try to place these shadow constants, the names of the __esan_* -// interface functions, and the ToolType enum into a header shared between -// llvm and compiler-rt. -struct ShadowMemoryParams { - uint64_t ShadowMask; - uint64_t ShadowOffs[3]; -}; - -static const ShadowMemoryParams ShadowParams47 = { - 0x00000fffffffffffull, - { - 0x0000130000000000ull, 0x0000220000000000ull, 0x0000440000000000ull, - }}; - -static const ShadowMemoryParams ShadowParams40 = { - 0x0fffffffffull, - { - 0x1300000000ull, 0x2200000000ull, 0x4400000000ull, - }}; - -// This array is indexed by the ToolType enum. -static const int ShadowScale[] = { - 0, // ESAN_None. - 2, // ESAN_CacheFrag: 4B:1B, so 4 to 1 == >>2. - 6, // ESAN_WorkingSet: 64B:1B, so 64 to 1 == >>6. -}; - -// MaxStructCounterNameSize is a soft size limit to avoid insanely long -// names for those extremely large structs. -static const unsigned MaxStructCounterNameSize = 512; - -namespace { - -static EfficiencySanitizerOptions -OverrideOptionsFromCL(EfficiencySanitizerOptions Options) { - if (ClToolCacheFrag) - Options.ToolType = EfficiencySanitizerOptions::ESAN_CacheFrag; - else if (ClToolWorkingSet) - Options.ToolType = EfficiencySanitizerOptions::ESAN_WorkingSet; - - // Direct opt invocation with no params will have the default ESAN_None. - // We run the default tool in that case. - if (Options.ToolType == EfficiencySanitizerOptions::ESAN_None) - Options.ToolType = EfficiencySanitizerOptions::ESAN_CacheFrag; - - return Options; -} - -/// EfficiencySanitizer: instrument each module to find performance issues. -class EfficiencySanitizer : public ModulePass { -public: - EfficiencySanitizer( - const EfficiencySanitizerOptions &Opts = EfficiencySanitizerOptions()) - : ModulePass(ID), Options(OverrideOptionsFromCL(Opts)) {} - StringRef getPassName() const override; - void getAnalysisUsage(AnalysisUsage &AU) const override; - bool runOnModule(Module &M) override; - static char ID; - -private: - bool initOnModule(Module &M); - void initializeCallbacks(Module &M); - bool shouldIgnoreStructType(StructType *StructTy); - void createStructCounterName( - StructType *StructTy, SmallString &NameStr); - void createCacheFragAuxGV( - Module &M, const DataLayout &DL, StructType *StructTy, - GlobalVariable *&TypeNames, GlobalVariable *&Offsets, GlobalVariable *&Size); - GlobalVariable *createCacheFragInfoGV(Module &M, const DataLayout &DL, - Constant *UnitName); - Constant *createEsanInitToolInfoArg(Module &M, const DataLayout &DL); - void createDestructor(Module &M, Constant *ToolInfoArg); - bool runOnFunction(Function &F, Module &M); - bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL); - bool instrumentMemIntrinsic(MemIntrinsic *MI); - bool instrumentGetElementPtr(Instruction *I, Module &M); - bool insertCounterUpdate(Instruction *I, StructType *StructTy, - unsigned CounterIdx); - unsigned getFieldCounterIdx(StructType *StructTy) { - return 0; - } - unsigned getArrayCounterIdx(StructType *StructTy) { - return StructTy->getNumElements(); - } - unsigned getStructCounterSize(StructType *StructTy) { - // The struct counter array includes: - // - one counter for each struct field, - // - one counter for the struct access within an array. - return (StructTy->getNumElements()/*field*/ + 1/*array*/); - } - bool shouldIgnoreMemoryAccess(Instruction *I); - int getMemoryAccessFuncIndex(Value *Addr, const DataLayout &DL); - Value *appToShadow(Value *Shadow, IRBuilder<> &IRB); - bool instrumentFastpath(Instruction *I, const DataLayout &DL, bool IsStore, - Value *Addr, unsigned Alignment); - // Each tool has its own fastpath routine: - bool instrumentFastpathCacheFrag(Instruction *I, const DataLayout &DL, - Value *Addr, unsigned Alignment); - bool instrumentFastpathWorkingSet(Instruction *I, const DataLayout &DL, - Value *Addr, unsigned Alignment); - - EfficiencySanitizerOptions Options; - LLVMContext *Ctx; - Type *IntptrTy; - // Our slowpath involves callouts to the runtime library. - // Access sizes are powers of two: 1, 2, 4, 8, 16. - static const size_t NumberOfAccessSizes = 5; - FunctionCallee EsanAlignedLoad[NumberOfAccessSizes]; - FunctionCallee EsanAlignedStore[NumberOfAccessSizes]; - FunctionCallee EsanUnalignedLoad[NumberOfAccessSizes]; - FunctionCallee EsanUnalignedStore[NumberOfAccessSizes]; - // For irregular sizes of any alignment: - FunctionCallee EsanUnalignedLoadN, EsanUnalignedStoreN; - FunctionCallee MemmoveFn, MemcpyFn, MemsetFn; - Function *EsanCtorFunction; - Function *EsanDtorFunction; - // Remember the counter variable for each struct type to avoid - // recomputing the variable name later during instrumentation. - std::map StructTyMap; - ShadowMemoryParams ShadowParams; -}; -} // namespace - -char EfficiencySanitizer::ID = 0; -INITIALIZE_PASS_BEGIN( - EfficiencySanitizer, "esan", - "EfficiencySanitizer: finds performance issues.", false, false) -INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) -INITIALIZE_PASS_END( - EfficiencySanitizer, "esan", - "EfficiencySanitizer: finds performance issues.", false, false) - -StringRef EfficiencySanitizer::getPassName() const { - return "EfficiencySanitizer"; -} - -void EfficiencySanitizer::getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); -} - -ModulePass * -llvm::createEfficiencySanitizerPass(const EfficiencySanitizerOptions &Options) { - return new EfficiencySanitizer(Options); -} - -void EfficiencySanitizer::initializeCallbacks(Module &M) { - IRBuilder<> IRB(M.getContext()); - // Initialize the callbacks. - for (size_t Idx = 0; Idx < NumberOfAccessSizes; ++Idx) { - const unsigned ByteSize = 1U << Idx; - std::string ByteSizeStr = utostr(ByteSize); - // We'll inline the most common (i.e., aligned and frequent sizes) - // load + store instrumentation: these callouts are for the slowpath. - SmallString<32> AlignedLoadName("__esan_aligned_load" + ByteSizeStr); - EsanAlignedLoad[Idx] = M.getOrInsertFunction( - AlignedLoadName, IRB.getVoidTy(), IRB.getInt8PtrTy()); - SmallString<32> AlignedStoreName("__esan_aligned_store" + ByteSizeStr); - EsanAlignedStore[Idx] = M.getOrInsertFunction( - AlignedStoreName, IRB.getVoidTy(), IRB.getInt8PtrTy()); - SmallString<32> UnalignedLoadName("__esan_unaligned_load" + ByteSizeStr); - EsanUnalignedLoad[Idx] = M.getOrInsertFunction( - UnalignedLoadName, IRB.getVoidTy(), IRB.getInt8PtrTy()); - SmallString<32> UnalignedStoreName("__esan_unaligned_store" + ByteSizeStr); - EsanUnalignedStore[Idx] = M.getOrInsertFunction( - UnalignedStoreName, IRB.getVoidTy(), IRB.getInt8PtrTy()); - } - EsanUnalignedLoadN = M.getOrInsertFunction( - "__esan_unaligned_loadN", IRB.getVoidTy(), IRB.getInt8PtrTy(), IntptrTy); - EsanUnalignedStoreN = M.getOrInsertFunction( - "__esan_unaligned_storeN", IRB.getVoidTy(), IRB.getInt8PtrTy(), IntptrTy); - MemmoveFn = - M.getOrInsertFunction("memmove", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), - IRB.getInt8PtrTy(), IntptrTy); - MemcpyFn = - M.getOrInsertFunction("memcpy", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), - IRB.getInt8PtrTy(), IntptrTy); - MemsetFn = - M.getOrInsertFunction("memset", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), - IRB.getInt32Ty(), IntptrTy); -} - -bool EfficiencySanitizer::shouldIgnoreStructType(StructType *StructTy) { - if (StructTy == nullptr || StructTy->isOpaque() /* no struct body */) - return true; - return false; -} - -void EfficiencySanitizer::createStructCounterName( - StructType *StructTy, SmallString &NameStr) { - // Append NumFields and field type ids to avoid struct conflicts - // with the same name but different fields. - if (StructTy->hasName()) - NameStr += StructTy->getName(); - else - NameStr += "struct.anon"; - // We allow the actual size of the StructCounterName to be larger than - // MaxStructCounterNameSize and append $NumFields and at least one - // field type id. - // Append $NumFields. - NameStr += "$"; - Twine(StructTy->getNumElements()).toVector(NameStr); - // Append struct field type ids in the reverse order. - for (int i = StructTy->getNumElements() - 1; i >= 0; --i) { - NameStr += "$"; - Twine(StructTy->getElementType(i)->getTypeID()).toVector(NameStr); - if (NameStr.size() >= MaxStructCounterNameSize) - break; - } - if (StructTy->isLiteral()) { - // End with $ for literal struct. - NameStr += "$"; - } -} - -// Create global variables with auxiliary information (e.g., struct field size, -// offset, and type name) for better user report. -void EfficiencySanitizer::createCacheFragAuxGV( - Module &M, const DataLayout &DL, StructType *StructTy, - GlobalVariable *&TypeName, GlobalVariable *&Offset, - GlobalVariable *&Size) { - auto *Int8PtrTy = Type::getInt8PtrTy(*Ctx); - auto *Int32Ty = Type::getInt32Ty(*Ctx); - // FieldTypeName. - auto *TypeNameArrayTy = ArrayType::get(Int8PtrTy, StructTy->getNumElements()); - TypeName = new GlobalVariable(M, TypeNameArrayTy, true, - GlobalVariable::InternalLinkage, nullptr); - SmallVector TypeNameVec; - // FieldOffset. - auto *OffsetArrayTy = ArrayType::get(Int32Ty, StructTy->getNumElements()); - Offset = new GlobalVariable(M, OffsetArrayTy, true, - GlobalVariable::InternalLinkage, nullptr); - SmallVector OffsetVec; - // FieldSize - auto *SizeArrayTy = ArrayType::get(Int32Ty, StructTy->getNumElements()); - Size = new GlobalVariable(M, SizeArrayTy, true, - GlobalVariable::InternalLinkage, nullptr); - SmallVector SizeVec; - for (unsigned i = 0; i < StructTy->getNumElements(); ++i) { - Type *Ty = StructTy->getElementType(i); - std::string Str; - raw_string_ostream StrOS(Str); - Ty->print(StrOS); - TypeNameVec.push_back( - ConstantExpr::getPointerCast( - createPrivateGlobalForString(M, StrOS.str(), true), - Int8PtrTy)); - OffsetVec.push_back( - ConstantInt::get(Int32Ty, - DL.getStructLayout(StructTy)->getElementOffset(i))); - SizeVec.push_back(ConstantInt::get(Int32Ty, - DL.getTypeAllocSize(Ty))); - } - TypeName->setInitializer(ConstantArray::get(TypeNameArrayTy, TypeNameVec)); - Offset->setInitializer(ConstantArray::get(OffsetArrayTy, OffsetVec)); - Size->setInitializer(ConstantArray::get(SizeArrayTy, SizeVec)); -} - -// Create the global variable for the cache-fragmentation tool. -GlobalVariable *EfficiencySanitizer::createCacheFragInfoGV( - Module &M, const DataLayout &DL, Constant *UnitName) { - assert(Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag); - - auto *Int8PtrTy = Type::getInt8PtrTy(*Ctx); - auto *Int8PtrPtrTy = Int8PtrTy->getPointerTo(); - auto *Int32Ty = Type::getInt32Ty(*Ctx); - auto *Int32PtrTy = Type::getInt32PtrTy(*Ctx); - auto *Int64Ty = Type::getInt64Ty(*Ctx); - auto *Int64PtrTy = Type::getInt64PtrTy(*Ctx); - // This structure should be kept consistent with the StructInfo struct - // in the runtime library. - // struct StructInfo { - // const char *StructName; - // u32 Size; - // u32 NumFields; - // u32 *FieldOffset; // auxiliary struct field info. - // u32 *FieldSize; // auxiliary struct field info. - // const char **FieldTypeName; // auxiliary struct field info. - // u64 *FieldCounters; - // u64 *ArrayCounter; - // }; - auto *StructInfoTy = - StructType::get(Int8PtrTy, Int32Ty, Int32Ty, Int32PtrTy, Int32PtrTy, - Int8PtrPtrTy, Int64PtrTy, Int64PtrTy); - auto *StructInfoPtrTy = StructInfoTy->getPointerTo(); - // This structure should be kept consistent with the CacheFragInfo struct - // in the runtime library. - // struct CacheFragInfo { - // const char *UnitName; - // u32 NumStructs; - // StructInfo *Structs; - // }; - auto *CacheFragInfoTy = StructType::get(Int8PtrTy, Int32Ty, StructInfoPtrTy); - - std::vector Vec = M.getIdentifiedStructTypes(); - unsigned NumStructs = 0; - SmallVector Initializers; - - for (auto &StructTy : Vec) { - if (shouldIgnoreStructType(StructTy)) { - ++NumIgnoredStructs; - continue; - } - ++NumStructs; - - // StructName. - SmallString CounterNameStr; - createStructCounterName(StructTy, CounterNameStr); - GlobalVariable *StructCounterName = createPrivateGlobalForString( - M, CounterNameStr, /*AllowMerging*/true); - - // Counters. - // We create the counter array with StructCounterName and weak linkage - // so that the structs with the same name and layout from different - // compilation units will be merged into one. - auto *CounterArrayTy = ArrayType::get(Int64Ty, - getStructCounterSize(StructTy)); - GlobalVariable *Counters = - new GlobalVariable(M, CounterArrayTy, false, - GlobalVariable::WeakAnyLinkage, - ConstantAggregateZero::get(CounterArrayTy), - CounterNameStr); - - // Remember the counter variable for each struct type. - StructTyMap.insert(std::pair(StructTy, Counters)); - - // We pass the field type name array, offset array, and size array to - // the runtime for better reporting. - GlobalVariable *TypeName = nullptr, *Offset = nullptr, *Size = nullptr; - if (ClAuxFieldInfo) - createCacheFragAuxGV(M, DL, StructTy, TypeName, Offset, Size); - - Constant *FieldCounterIdx[2]; - FieldCounterIdx[0] = ConstantInt::get(Int32Ty, 0); - FieldCounterIdx[1] = ConstantInt::get(Int32Ty, - getFieldCounterIdx(StructTy)); - Constant *ArrayCounterIdx[2]; - ArrayCounterIdx[0] = ConstantInt::get(Int32Ty, 0); - ArrayCounterIdx[1] = ConstantInt::get(Int32Ty, - getArrayCounterIdx(StructTy)); - Initializers.push_back(ConstantStruct::get( - StructInfoTy, - ConstantExpr::getPointerCast(StructCounterName, Int8PtrTy), - ConstantInt::get(Int32Ty, - DL.getStructLayout(StructTy)->getSizeInBytes()), - ConstantInt::get(Int32Ty, StructTy->getNumElements()), - Offset == nullptr ? ConstantPointerNull::get(Int32PtrTy) - : ConstantExpr::getPointerCast(Offset, Int32PtrTy), - Size == nullptr ? ConstantPointerNull::get(Int32PtrTy) - : ConstantExpr::getPointerCast(Size, Int32PtrTy), - TypeName == nullptr - ? ConstantPointerNull::get(Int8PtrPtrTy) - : ConstantExpr::getPointerCast(TypeName, Int8PtrPtrTy), - ConstantExpr::getGetElementPtr(CounterArrayTy, Counters, - FieldCounterIdx), - ConstantExpr::getGetElementPtr(CounterArrayTy, Counters, - ArrayCounterIdx))); - } - // Structs. - Constant *StructInfo; - if (NumStructs == 0) { - StructInfo = ConstantPointerNull::get(StructInfoPtrTy); - } else { - auto *StructInfoArrayTy = ArrayType::get(StructInfoTy, NumStructs); - StructInfo = ConstantExpr::getPointerCast( - new GlobalVariable(M, StructInfoArrayTy, false, - GlobalVariable::InternalLinkage, - ConstantArray::get(StructInfoArrayTy, Initializers)), - StructInfoPtrTy); - } - - auto *CacheFragInfoGV = new GlobalVariable( - M, CacheFragInfoTy, true, GlobalVariable::InternalLinkage, - ConstantStruct::get(CacheFragInfoTy, UnitName, - ConstantInt::get(Int32Ty, NumStructs), StructInfo)); - return CacheFragInfoGV; -} - -// Create the tool-specific argument passed to EsanInit and EsanExit. -Constant *EfficiencySanitizer::createEsanInitToolInfoArg(Module &M, - const DataLayout &DL) { - // This structure contains tool-specific information about each compilation - // unit (module) and is passed to the runtime library. - GlobalVariable *ToolInfoGV = nullptr; - - auto *Int8PtrTy = Type::getInt8PtrTy(*Ctx); - // Compilation unit name. - auto *UnitName = ConstantExpr::getPointerCast( - createPrivateGlobalForString(M, M.getModuleIdentifier(), true), - Int8PtrTy); - - // Create the tool-specific variable. - if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag) - ToolInfoGV = createCacheFragInfoGV(M, DL, UnitName); - - if (ToolInfoGV != nullptr) - return ConstantExpr::getPointerCast(ToolInfoGV, Int8PtrTy); - - // Create the null pointer if no tool-specific variable created. - return ConstantPointerNull::get(Int8PtrTy); -} - -void EfficiencySanitizer::createDestructor(Module &M, Constant *ToolInfoArg) { - PointerType *Int8PtrTy = Type::getInt8PtrTy(*Ctx); - EsanDtorFunction = Function::Create(FunctionType::get(Type::getVoidTy(*Ctx), - false), - GlobalValue::InternalLinkage, - EsanModuleDtorName, &M); - ReturnInst::Create(*Ctx, BasicBlock::Create(*Ctx, "", EsanDtorFunction)); - IRBuilder<> IRB_Dtor(EsanDtorFunction->getEntryBlock().getTerminator()); - FunctionCallee EsanExit = - M.getOrInsertFunction(EsanExitName, IRB_Dtor.getVoidTy(), Int8PtrTy); - IRB_Dtor.CreateCall(EsanExit, {ToolInfoArg}); - appendToGlobalDtors(M, EsanDtorFunction, EsanCtorAndDtorPriority); -} - -bool EfficiencySanitizer::initOnModule(Module &M) { - - Triple TargetTriple(M.getTargetTriple()); - if (TargetTriple.isMIPS64()) - ShadowParams = ShadowParams40; - else - ShadowParams = ShadowParams47; - - Ctx = &M.getContext(); - const DataLayout &DL = M.getDataLayout(); - IRBuilder<> IRB(M.getContext()); - IntegerType *OrdTy = IRB.getInt32Ty(); - PointerType *Int8PtrTy = Type::getInt8PtrTy(*Ctx); - IntptrTy = DL.getIntPtrType(M.getContext()); - // Create the variable passed to EsanInit and EsanExit. - Constant *ToolInfoArg = createEsanInitToolInfoArg(M, DL); - // Constructor - // We specify the tool type both in the EsanWhichToolName global - // and as an arg to the init routine as a sanity check. - std::tie(EsanCtorFunction, std::ignore) = createSanitizerCtorAndInitFunctions( - M, EsanModuleCtorName, EsanInitName, /*InitArgTypes=*/{OrdTy, Int8PtrTy}, - /*InitArgs=*/{ - ConstantInt::get(OrdTy, static_cast(Options.ToolType)), - ToolInfoArg}); - appendToGlobalCtors(M, EsanCtorFunction, EsanCtorAndDtorPriority); - - createDestructor(M, ToolInfoArg); - - new GlobalVariable(M, OrdTy, true, - GlobalValue::WeakAnyLinkage, - ConstantInt::get(OrdTy, - static_cast(Options.ToolType)), - EsanWhichToolName); - - return true; -} - -Value *EfficiencySanitizer::appToShadow(Value *Shadow, IRBuilder<> &IRB) { - // Shadow = ((App & Mask) + Offs) >> Scale - Shadow = IRB.CreateAnd(Shadow, ConstantInt::get(IntptrTy, ShadowParams.ShadowMask)); - uint64_t Offs; - int Scale = ShadowScale[Options.ToolType]; - if (Scale <= 2) - Offs = ShadowParams.ShadowOffs[Scale]; - else - Offs = ShadowParams.ShadowOffs[0] << Scale; - Shadow = IRB.CreateAdd(Shadow, ConstantInt::get(IntptrTy, Offs)); - if (Scale > 0) - Shadow = IRB.CreateLShr(Shadow, Scale); - return Shadow; -} - -bool EfficiencySanitizer::shouldIgnoreMemoryAccess(Instruction *I) { - if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag) { - // We'd like to know about cache fragmentation in vtable accesses and - // constant data references, so we do not currently ignore anything. - return false; - } else if (Options.ToolType == EfficiencySanitizerOptions::ESAN_WorkingSet) { - // TODO: the instrumentation disturbs the data layout on the stack, so we - // may want to add an option to ignore stack references (if we can - // distinguish them) to reduce overhead. - } - // TODO(bruening): future tools will be returning true for some cases. - return false; -} - -bool EfficiencySanitizer::runOnModule(Module &M) { - bool Res = initOnModule(M); - initializeCallbacks(M); - for (auto &F : M) { - Res |= runOnFunction(F, M); - } - return Res; -} - -bool EfficiencySanitizer::runOnFunction(Function &F, Module &M) { - // This is required to prevent instrumenting the call to __esan_init from - // within the module constructor. - if (&F == EsanCtorFunction) - return false; - SmallVector LoadsAndStores; - SmallVector MemIntrinCalls; - SmallVector GetElementPtrs; - bool Res = false; - const DataLayout &DL = M.getDataLayout(); - const TargetLibraryInfo *TLI = - &getAnalysis().getTLI(); - - for (auto &BB : F) { - for (auto &Inst : BB) { - if ((isa(Inst) || isa(Inst) || - isa(Inst) || isa(Inst)) && - !shouldIgnoreMemoryAccess(&Inst)) - LoadsAndStores.push_back(&Inst); - else if (isa(Inst)) - MemIntrinCalls.push_back(&Inst); - else if (isa(Inst)) - GetElementPtrs.push_back(&Inst); - else if (CallInst *CI = dyn_cast(&Inst)) - maybeMarkSanitizerLibraryCallNoBuiltin(CI, TLI); - } - } - - if (ClInstrumentLoadsAndStores) { - for (auto Inst : LoadsAndStores) { - Res |= instrumentLoadOrStore(Inst, DL); - } - } - - if (ClInstrumentMemIntrinsics) { - for (auto Inst : MemIntrinCalls) { - Res |= instrumentMemIntrinsic(cast(Inst)); - } - } - - if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag) { - for (auto Inst : GetElementPtrs) { - Res |= instrumentGetElementPtr(Inst, M); - } - } - - return Res; -} - -bool EfficiencySanitizer::instrumentLoadOrStore(Instruction *I, - const DataLayout &DL) { - IRBuilder<> IRB(I); - bool IsStore; - Value *Addr; - unsigned Alignment; - if (LoadInst *Load = dyn_cast(I)) { - IsStore = false; - Alignment = Load->getAlignment(); - Addr = Load->getPointerOperand(); - } else if (StoreInst *Store = dyn_cast(I)) { - IsStore = true; - Alignment = Store->getAlignment(); - Addr = Store->getPointerOperand(); - } else if (AtomicRMWInst *RMW = dyn_cast(I)) { - IsStore = true; - Alignment = 0; - Addr = RMW->getPointerOperand(); - } else if (AtomicCmpXchgInst *Xchg = dyn_cast(I)) { - IsStore = true; - Alignment = 0; - Addr = Xchg->getPointerOperand(); - } else - llvm_unreachable("Unsupported mem access type"); - - Type *OrigTy = cast(Addr->getType())->getElementType(); - const uint32_t TypeSizeBytes = DL.getTypeStoreSizeInBits(OrigTy) / 8; - FunctionCallee OnAccessFunc = nullptr; - - // Convert 0 to the default alignment. - if (Alignment == 0) - Alignment = DL.getPrefTypeAlignment(OrigTy); - - if (IsStore) - NumInstrumentedStores++; - else - NumInstrumentedLoads++; - int Idx = getMemoryAccessFuncIndex(Addr, DL); - if (Idx < 0) { - OnAccessFunc = IsStore ? EsanUnalignedStoreN : EsanUnalignedLoadN; - IRB.CreateCall(OnAccessFunc, - {IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()), - ConstantInt::get(IntptrTy, TypeSizeBytes)}); - } else { - if (ClInstrumentFastpath && - instrumentFastpath(I, DL, IsStore, Addr, Alignment)) { - NumFastpaths++; - return true; - } - if (Alignment == 0 || (Alignment % TypeSizeBytes) == 0) - OnAccessFunc = IsStore ? EsanAlignedStore[Idx] : EsanAlignedLoad[Idx]; - else - OnAccessFunc = IsStore ? EsanUnalignedStore[Idx] : EsanUnalignedLoad[Idx]; - IRB.CreateCall(OnAccessFunc, - IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy())); - } - return true; -} - -// It's simplest to replace the memset/memmove/memcpy intrinsics with -// calls that the runtime library intercepts. -// Our pass is late enough that calls should not turn back into intrinsics. -bool EfficiencySanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) { - IRBuilder<> IRB(MI); - bool Res = false; - if (isa(MI)) { - IRB.CreateCall( - MemsetFn, - {IRB.CreatePointerCast(MI->getArgOperand(0), IRB.getInt8PtrTy()), - IRB.CreateIntCast(MI->getArgOperand(1), IRB.getInt32Ty(), false), - IRB.CreateIntCast(MI->getArgOperand(2), IntptrTy, false)}); - MI->eraseFromParent(); - Res = true; - } else if (isa(MI)) { - IRB.CreateCall( - isa(MI) ? MemcpyFn : MemmoveFn, - {IRB.CreatePointerCast(MI->getArgOperand(0), IRB.getInt8PtrTy()), - IRB.CreatePointerCast(MI->getArgOperand(1), IRB.getInt8PtrTy()), - IRB.CreateIntCast(MI->getArgOperand(2), IntptrTy, false)}); - MI->eraseFromParent(); - Res = true; - } else - llvm_unreachable("Unsupported mem intrinsic type"); - return Res; -} - -bool EfficiencySanitizer::instrumentGetElementPtr(Instruction *I, Module &M) { - GetElementPtrInst *GepInst = dyn_cast(I); - bool Res = false; - if (GepInst == nullptr || GepInst->getNumIndices() == 1) { - ++NumIgnoredGEPs; - return false; - } - Type *SourceTy = GepInst->getSourceElementType(); - StructType *StructTy = nullptr; - ConstantInt *Idx; - // Check if GEP calculates address from a struct array. - if (isa(SourceTy)) { - StructTy = cast(SourceTy); - Idx = dyn_cast(GepInst->getOperand(1)); - if ((Idx == nullptr || Idx->getSExtValue() != 0) && - !shouldIgnoreStructType(StructTy) && StructTyMap.count(StructTy) != 0) - Res |= insertCounterUpdate(I, StructTy, getArrayCounterIdx(StructTy)); - } - // Iterate all (except the first and the last) idx within each GEP instruction - // for possible nested struct field address calculation. - for (unsigned i = 1; i < GepInst->getNumIndices(); ++i) { - SmallVector IdxVec(GepInst->idx_begin(), - GepInst->idx_begin() + i); - Type *Ty = GetElementPtrInst::getIndexedType(SourceTy, IdxVec); - unsigned CounterIdx = 0; - if (isa(Ty)) { - ArrayType *ArrayTy = cast(Ty); - StructTy = dyn_cast(ArrayTy->getElementType()); - if (shouldIgnoreStructType(StructTy) || StructTyMap.count(StructTy) == 0) - continue; - // The last counter for struct array access. - CounterIdx = getArrayCounterIdx(StructTy); - } else if (isa(Ty)) { - StructTy = cast(Ty); - if (shouldIgnoreStructType(StructTy) || StructTyMap.count(StructTy) == 0) - continue; - // Get the StructTy's subfield index. - Idx = cast(GepInst->getOperand(i+1)); - assert(Idx->getSExtValue() >= 0 && - Idx->getSExtValue() < StructTy->getNumElements()); - CounterIdx = getFieldCounterIdx(StructTy) + Idx->getSExtValue(); - } - Res |= insertCounterUpdate(I, StructTy, CounterIdx); - } - if (Res) - ++NumInstrumentedGEPs; - else - ++NumIgnoredGEPs; - return Res; -} - -bool EfficiencySanitizer::insertCounterUpdate(Instruction *I, - StructType *StructTy, - unsigned CounterIdx) { - GlobalVariable *CounterArray = StructTyMap[StructTy]; - if (CounterArray == nullptr) - return false; - IRBuilder<> IRB(I); - Constant *Indices[2]; - // Xref http://llvm.org/docs/LangRef.html#i-getelementptr and - // http://llvm.org/docs/GetElementPtr.html. - // The first index of the GEP instruction steps through the first operand, - // i.e., the array itself. - Indices[0] = ConstantInt::get(IRB.getInt32Ty(), 0); - // The second index is the index within the array. - Indices[1] = ConstantInt::get(IRB.getInt32Ty(), CounterIdx); - Constant *Counter = - ConstantExpr::getGetElementPtr( - ArrayType::get(IRB.getInt64Ty(), getStructCounterSize(StructTy)), - CounterArray, Indices); - Value *Load = IRB.CreateLoad(IRB.getInt64Ty(), Counter); - IRB.CreateStore(IRB.CreateAdd(Load, ConstantInt::get(IRB.getInt64Ty(), 1)), - Counter); - return true; -} - -int EfficiencySanitizer::getMemoryAccessFuncIndex(Value *Addr, - const DataLayout &DL) { - Type *OrigPtrTy = Addr->getType(); - Type *OrigTy = cast(OrigPtrTy)->getElementType(); - assert(OrigTy->isSized()); - // The size is always a multiple of 8. - uint32_t TypeSizeBytes = DL.getTypeStoreSizeInBits(OrigTy) / 8; - if (TypeSizeBytes != 1 && TypeSizeBytes != 2 && TypeSizeBytes != 4 && - TypeSizeBytes != 8 && TypeSizeBytes != 16) { - // Irregular sizes do not have per-size call targets. - NumAccessesWithIrregularSize++; - return -1; - } - size_t Idx = countTrailingZeros(TypeSizeBytes); - assert(Idx < NumberOfAccessSizes); - return Idx; -} - -bool EfficiencySanitizer::instrumentFastpath(Instruction *I, - const DataLayout &DL, bool IsStore, - Value *Addr, unsigned Alignment) { - if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag) { - return instrumentFastpathCacheFrag(I, DL, Addr, Alignment); - } else if (Options.ToolType == EfficiencySanitizerOptions::ESAN_WorkingSet) { - return instrumentFastpathWorkingSet(I, DL, Addr, Alignment); - } - return false; -} - -bool EfficiencySanitizer::instrumentFastpathCacheFrag(Instruction *I, - const DataLayout &DL, - Value *Addr, - unsigned Alignment) { - // Do nothing. - return true; // Return true to avoid slowpath instrumentation. -} - -bool EfficiencySanitizer::instrumentFastpathWorkingSet( - Instruction *I, const DataLayout &DL, Value *Addr, unsigned Alignment) { - assert(ShadowScale[Options.ToolType] == 6); // The code below assumes this - IRBuilder<> IRB(I); - Type *OrigTy = cast(Addr->getType())->getElementType(); - const uint32_t TypeSize = DL.getTypeStoreSizeInBits(OrigTy); - // Bail to the slowpath if the access might touch multiple cache lines. - // An access aligned to its size is guaranteed to be intra-cache-line. - // getMemoryAccessFuncIndex has already ruled out a size larger than 16 - // and thus larger than a cache line for platforms this tool targets - // (and our shadow memory setup assumes 64-byte cache lines). - assert(TypeSize <= 128); - if (!(TypeSize == 8 || - (Alignment % (TypeSize / 8)) == 0)) { - if (ClAssumeIntraCacheLine) - ++NumAssumedIntraCacheLine; - else - return false; - } - - // We inline instrumentation to set the corresponding shadow bits for - // each cache line touched by the application. Here we handle a single - // load or store where we've already ruled out the possibility that it - // might touch more than one cache line and thus we simply update the - // shadow memory for a single cache line. - // Our shadow memory model is fine with races when manipulating shadow values. - // We generate the following code: - // - // const char BitMask = 0x81; - // char *ShadowAddr = appToShadow(AppAddr); - // if ((*ShadowAddr & BitMask) != BitMask) - // *ShadowAddr |= Bitmask; - // - Value *AddrPtr = IRB.CreatePointerCast(Addr, IntptrTy); - Value *ShadowPtr = appToShadow(AddrPtr, IRB); - Type *ShadowTy = IntegerType::get(*Ctx, 8U); - Type *ShadowPtrTy = PointerType::get(ShadowTy, 0); - // The bottom bit is used for the current sampling period's working set. - // The top bit is used for the total working set. We set both on each - // memory access, if they are not already set. - Value *ValueMask = ConstantInt::get(ShadowTy, 0x81); // 10000001B - - Value *OldValue = - IRB.CreateLoad(ShadowTy, IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy)); - // The AND and CMP will be turned into a TEST instruction by the compiler. - Value *Cmp = IRB.CreateICmpNE(IRB.CreateAnd(OldValue, ValueMask), ValueMask); - Instruction *CmpTerm = SplitBlockAndInsertIfThen(Cmp, I, false); - // FIXME: do I need to call SetCurrentDebugLocation? - IRB.SetInsertPoint(CmpTerm); - // We use OR to set the shadow bits to avoid corrupting the middle 6 bits, - // which are used by the runtime library. - Value *NewVal = IRB.CreateOr(OldValue, ValueMask); - IRB.CreateStore(NewVal, IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy)); - IRB.SetInsertPoint(I); - - return true; -} Index: llvm/lib/Transforms/Instrumentation/Instrumentation.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/Instrumentation.cpp +++ llvm/lib/Transforms/Instrumentation/Instrumentation.cpp @@ -116,7 +116,6 @@ initializeThreadSanitizerLegacyPassPass(Registry); initializeSanitizerCoverageModulePass(Registry); initializeDataFlowSanitizerPass(Registry); - initializeEfficiencySanitizerPass(Registry); } /// LLVMInitializeInstrumentation - C binding for Index: llvm/test/Instrumentation/EfficiencySanitizer/str-nobuiltin.ll =================================================================== --- llvm/test/Instrumentation/EfficiencySanitizer/str-nobuiltin.ll +++ /dev/null @@ -1,33 +0,0 @@ -; Test marking string functions as nobuiltin in efficiency sanitizer. -; -; RUN: opt < %s -esan -S | FileCheck %s -target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" -target triple = "x86_64-unknown-linux-gnu" - -declare i8* @memchr(i8* %a, i32 %b, i64 %c) -declare i32 @memcmp(i8* %a, i8* %b, i64 %c) -declare i32 @strcmp(i8* %a, i8* %b) -declare i8* @strcpy(i8* %a, i8* %b) -declare i8* @stpcpy(i8* %a, i8* %b) -declare i64 @strlen(i8* %a) -declare i64 @strnlen(i8* %a, i64 %b) - -; CHECK: call{{.*}}@memchr{{.*}} #[[ATTR:[0-9]+]] -; CHECK: call{{.*}}@memcmp{{.*}} #[[ATTR]] -; CHECK: call{{.*}}@strcmp{{.*}} #[[ATTR]] -; CHECK: call{{.*}}@strcpy{{.*}} #[[ATTR]] -; CHECK: call{{.*}}@stpcpy{{.*}} #[[ATTR]] -; CHECK: call{{.*}}@strlen{{.*}} #[[ATTR]] -; CHECK: call{{.*}}@strnlen{{.*}} #[[ATTR]] -; attributes #[[ATTR]] = { nobuiltin } - -define void @f1(i8* %a, i8* %b) nounwind uwtable { - tail call i8* @memchr(i8* %a, i32 1, i64 12) - tail call i32 @memcmp(i8* %a, i8* %b, i64 12) - tail call i32 @strcmp(i8* %a, i8* %b) - tail call i8* @strcpy(i8* %a, i8* %b) - tail call i8* @stpcpy(i8* %a, i8* %b) - tail call i64 @strlen(i8* %a) - tail call i64 @strnlen(i8* %a, i64 12) - ret void -} Index: llvm/test/Instrumentation/EfficiencySanitizer/struct_field_count_basic.ll =================================================================== --- llvm/test/Instrumentation/EfficiencySanitizer/struct_field_count_basic.ll +++ /dev/null @@ -1,157 +0,0 @@ -; Test basic EfficiencySanitizer struct field count instrumentation. -; -; RUN: opt < %s -esan -esan-cache-frag -S | FileCheck %s - -%struct.A = type { i32, i32 } -%union.U = type { double } -%struct.C = type { %struct.anon, %union.anon, [10 x i8] } -%struct.anon = type { i32, i32 } -%union.anon = type { double } - -; CHECK: @0 = private unnamed_addr constant [8 x i8] c"\00", align 1 -; CHECK-NEXT: @1 = private unnamed_addr constant [17 x i8] c"struct.A$2$11$11\00", align 1 -; CHECK-NEXT: @"struct.A$2$11$11" = weak global [3 x i64] zeroinitializer -; CHECK-NEXT: @2 = internal constant [2 x i8*] [i8* getelementptr inbounds ([4 x i8], [4 x i8]* @5, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @6, i32 0, i32 0)] -; CHECK-NEXT: @3 = internal constant [2 x i32] [i32 0, i32 4] -; CHECK-NEXT: @4 = internal constant [2 x i32] [i32 4, i32 4] -; CHECK-NEXT: @5 = private unnamed_addr constant [4 x i8] c"i32\00", align 1 -; CHECK-NEXT: @6 = private unnamed_addr constant [4 x i8] c"i32\00", align 1 -; CHECK-NEXT: @7 = private unnamed_addr constant [12 x i8] c"union.U$1$3\00", align 1 -; CHECK-NEXT: @"union.U$1$3" = weak global [2 x i64] zeroinitializer -; CHECK-NEXT: @8 = internal constant [1 x i8*] [i8* getelementptr inbounds ([7 x i8], [7 x i8]* @11, i32 0, i32 0)] -; CHECK-NEXT: @9 = internal constant [1 x i32] zeroinitializer -; CHECK-NEXT: @10 = internal constant [1 x i32] [i32 8] -; CHECK-NEXT: @11 = private unnamed_addr constant [7 x i8] c"double\00", align 1 -; CHECK-NEXT: @12 = private unnamed_addr constant [20 x i8] c"struct.C$3$14$13$13\00", align 1 -; CHECK-NEXT: @"struct.C$3$14$13$13" = weak global [4 x i64] zeroinitializer -; CHECK-NEXT: @13 = internal constant [3 x i8*] [i8* getelementptr inbounds ([33 x i8], [33 x i8]* @16, i32 0, i32 0), i8* getelementptr inbounds ([30 x i8], [30 x i8]* @17, i32 0, i32 0), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @18, i32 0, i32 0)] -; CHECK-NEXT: @14 = internal constant [3 x i32] [i32 0, i32 8, i32 16] -; CHECK-NEXT: @15 = internal constant [3 x i32] [i32 8, i32 8, i32 10] -; CHECK-NEXT: @16 = private unnamed_addr constant [33 x i8] c"%struct.anon = type { i32, i32 }\00", align 1 -; CHECK-NEXT: @17 = private unnamed_addr constant [30 x i8] c"%union.anon = type { double }\00", align 1 -; CHECK-NEXT: @18 = private unnamed_addr constant [10 x i8] c"[10 x i8]\00", align 1 -; CHECK-NEXT: @19 = private unnamed_addr constant [20 x i8] c"struct.anon$2$11$11\00", align 1 -; CHECK-NEXT: @"struct.anon$2$11$11" = weak global [3 x i64] zeroinitializer -; CHECK-NEXT: @20 = internal constant [2 x i8*] [i8* getelementptr inbounds ([4 x i8], [4 x i8]* @23, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @24, i32 0, i32 0)] -; CHECK-NEXT: @21 = internal constant [2 x i32] [i32 0, i32 4] -; CHECK-NEXT: @22 = internal constant [2 x i32] [i32 4, i32 4] -; CHECK-NEXT: @23 = private unnamed_addr constant [4 x i8] c"i32\00", align 1 -; CHECK-NEXT: @24 = private unnamed_addr constant [4 x i8] c"i32\00", align 1 -; CHECK-NEXT: @25 = private unnamed_addr constant [15 x i8] c"union.anon$1$3\00", align 1 -; CHECK-NEXT: @"union.anon$1$3" = weak global [2 x i64] zeroinitializer -; CHECK-NEXT: @26 = internal constant [1 x i8*] [i8* getelementptr inbounds ([7 x i8], [7 x i8]* @29, i32 0, i32 0)] -; CHECK-NEXT: @27 = internal constant [1 x i32] zeroinitializer -; CHECK-NEXT: @28 = internal constant [1 x i32] [i32 8] -; CHECK-NEXT: @29 = private unnamed_addr constant [7 x i8] c"double\00", align 1 -; CHECK-NEXT: @30 = internal global [5 x { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* }] [{ i8*, i32, i32, i32*, i32*, i8**, i64*, i64* } { i8* getelementptr inbounds ([17 x i8], [17 x i8]* @1, i32 0, i32 0), i32 8, i32 2, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @3, i32 0, i32 0), i32* getelementptr inbounds ([2 x i32], [2 x i32]* @4, i32 0, i32 0), i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @2, i32 0, i32 0), i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.A$2$11$11", i32 0, i32 0), i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.A$2$11$11", i32 0, i32 2) }, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* } { i8* getelementptr inbounds ([12 x i8], [12 x i8]* @7, i32 0, i32 0), i32 8, i32 1, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @9, i32 0, i32 0), i32* getelementptr inbounds ([1 x i32], [1 x i32]* @10, i32 0, i32 0), i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @8, i32 0, i32 0), i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"union.U$1$3", i32 0, i32 0), i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"union.U$1$3", i32 0, i32 1) }, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* } { i8* getelementptr inbounds ([20 x i8], [20 x i8]* @12, i32 0, i32 0), i32 32, i32 3, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @14, i32 0, i32 0), i32* getelementptr inbounds ([3 x i32], [3 x i32]* @15, i32 0, i32 0), i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @13, i32 0, i32 0), i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 0), i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) }, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* } { i8* getelementptr inbounds ([20 x i8], [20 x i8]* @19, i32 0, i32 0), i32 8, i32 2, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @21, i32 0, i32 0), i32* getelementptr inbounds ([2 x i32], [2 x i32]* @22, i32 0, i32 0), i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @20, i32 0, i32 0), i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.anon$2$11$11", i32 0, i32 0), i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.anon$2$11$11", i32 0, i32 2) }, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* } { i8* getelementptr inbounds ([15 x i8], [15 x i8]* @25, i32 0, i32 0), i32 8, i32 1, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @27, i32 0, i32 0), i32* getelementptr inbounds ([1 x i32], [1 x i32]* @28, i32 0, i32 0), i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @26, i32 0, i32 0), i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"union.anon$1$3", i32 0, i32 0), i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"union.anon$1$3", i32 0, i32 1) }] -; CHECK-NEXT: @31 = internal constant { i8*, i32, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* }* } { i8* getelementptr inbounds ([8 x i8], [8 x i8]* @0, i32 0, i32 0), i32 5, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* }* getelementptr inbounds ([5 x { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* }], [5 x { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* }]* @30, i32 0, i32 0) } - -define i32 @main() { -entry: - %a = alloca %struct.A, align 4 - %u = alloca %union.U, align 8 - %c = alloca [2 x %struct.C], align 16 - %k = alloca %struct.A*, align 8 - %x = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 0 - %y = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 1 - %f = bitcast %union.U* %u to float* - %d = bitcast %union.U* %u to double* - %arrayidx = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0 - %cs = getelementptr inbounds %struct.C, %struct.C* %arrayidx, i32 0, i32 0 - %x1 = getelementptr inbounds %struct.anon, %struct.anon* %cs, i32 0, i32 0 - %arrayidx2 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 1 - %cs3 = getelementptr inbounds %struct.C, %struct.C* %arrayidx2, i32 0, i32 0 - %y4 = getelementptr inbounds %struct.anon, %struct.anon* %cs3, i32 0, i32 1 - %arrayidx5 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0 - %cu = getelementptr inbounds %struct.C, %struct.C* %arrayidx5, i32 0, i32 1 - %f6 = bitcast %union.anon* %cu to float* - %arrayidx7 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 1 - %cu8 = getelementptr inbounds %struct.C, %struct.C* %arrayidx7, i32 0, i32 1 - %d9 = bitcast %union.anon* %cu8 to double* - %arrayidx10 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0 - %c11 = getelementptr inbounds %struct.C, %struct.C* %arrayidx10, i32 0, i32 2 - %arrayidx12 = getelementptr inbounds [10 x i8], [10 x i8]* %c11, i64 0, i64 2 - %k1 = load %struct.A*, %struct.A** %k, align 8 - %arrayidx13 = getelementptr inbounds %struct.A, %struct.A* %k1, i64 0 - ret i32 0 -} - -; CHECK: @llvm.global_ctors = {{.*}}@esan.module_ctor -; CHECK: @llvm.global_dtors = {{.*}}@esan.module_dtor - -; CHECK: %a = alloca %struct.A, align 4 -; CHECK-NEXT: %u = alloca %union.U, align 8 -; CHECK-NEXT: %c = alloca [2 x %struct.C], align 16 -; CHECK-NEXT: %k = alloca %struct.A*, align 8 -; CHECK-NEXT: %0 = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.A$2$11$11", i32 0, i32 0) -; CHECK-NEXT: %1 = add i64 %0, 1 -; CHECK-NEXT: store i64 %1, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.A$2$11$11", i32 0, i32 0) -; CHECK-NEXT: %x = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 0 -; CHECK-NEXT: %2 = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.A$2$11$11", i32 0, i32 1) -; CHECK-NEXT: %3 = add i64 %2, 1 -; CHECK-NEXT: store i64 %3, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.A$2$11$11", i32 0, i32 1) -; CHECK-NEXT: %y = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 1 -; CHECK-NEXT: %f = bitcast %union.U* %u to float* -; CHECK-NEXT: %d = bitcast %union.U* %u to double* -; CHECK-NEXT: %4 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %5 = add i64 %4, 1 -; CHECK-NEXT: store i64 %5, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %arrayidx = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0 -; CHECK-NEXT: %6 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 0) -; CHECK-NEXT: %7 = add i64 %6, 1 -; CHECK-NEXT: store i64 %7, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 0) -; CHECK-NEXT: %cs = getelementptr inbounds %struct.C, %struct.C* %arrayidx, i32 0, i32 0 -; CHECK-NEXT: %8 = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.anon$2$11$11", i32 0, i32 0) -; CHECK-NEXT: %9 = add i64 %8, 1 -; CHECK-NEXT: store i64 %9, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.anon$2$11$11", i32 0, i32 0) -; CHECK-NEXT: %x1 = getelementptr inbounds %struct.anon, %struct.anon* %cs, i32 0, i32 0 -; CHECK-NEXT: %10 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %11 = add i64 %10, 1 -; CHECK-NEXT: store i64 %11, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %arrayidx2 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 1 -; CHECK-NEXT: %12 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 0) -; CHECK-NEXT: %13 = add i64 %12, 1 -; CHECK-NEXT: store i64 %13, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 0) -; CHECK-NEXT: %cs3 = getelementptr inbounds %struct.C, %struct.C* %arrayidx2, i32 0, i32 0 -; CHECK-NEXT: %14 = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.anon$2$11$11", i32 0, i32 1) -; CHECK-NEXT: %15 = add i64 %14, 1 -; CHECK-NEXT: store i64 %15, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.anon$2$11$11", i32 0, i32 1) -; CHECK-NEXT: %y4 = getelementptr inbounds %struct.anon, %struct.anon* %cs3, i32 0, i32 1 -; CHECK-NEXT: %16 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %17 = add i64 %16, 1 -; CHECK-NEXT: store i64 %17, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %arrayidx5 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0 -; CHECK-NEXT: %18 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 1) -; CHECK-NEXT: %19 = add i64 %18, 1 -; CHECK-NEXT: store i64 %19, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 1) -; CHECK-NEXT: %cu = getelementptr inbounds %struct.C, %struct.C* %arrayidx5, i32 0, i32 1 -; CHECK-NEXT: %f6 = bitcast %union.anon* %cu to float* -; CHECK-NEXT: %20 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %21 = add i64 %20, 1 -; CHECK-NEXT: store i64 %21, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %arrayidx7 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 1 -; CHECK-NEXT: %22 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 1) -; CHECK-NEXT: %23 = add i64 %22, 1 -; CHECK-NEXT: store i64 %23, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 1) -; CHECK-NEXT: %cu8 = getelementptr inbounds %struct.C, %struct.C* %arrayidx7, i32 0, i32 1 -; CHECK-NEXT: %d9 = bitcast %union.anon* %cu8 to double* -; CHECK-NEXT: %24 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %25 = add i64 %24, 1 -; CHECK-NEXT: store i64 %25, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %arrayidx10 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0 -; CHECK-NEXT: %26 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 2) -; CHECK-NEXT: %27 = add i64 %26, 1 -; CHECK-NEXT: store i64 %27, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 2) -; CHECK-NEXT: %c11 = getelementptr inbounds %struct.C, %struct.C* %arrayidx10, i32 0, i32 2 -; CHECK-NEXT: %arrayidx12 = getelementptr inbounds [10 x i8], [10 x i8]* %c11, i64 0, i64 2 -; CHECK-NEXT: %k1 = load %struct.A*, %struct.A** %k, align 8 -; CHECK-NEXT: %arrayidx13 = getelementptr inbounds %struct.A, %struct.A* %k1, i64 0 -; CHECK-NEXT: ret i32 0 - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Top-level: - -; CHECK: define internal void @esan.module_ctor() -; CHECK: call void @__esan_init(i32 1, i8* bitcast ({ i8*, i32, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* }* }* @31 to i8*)) -; CHECK: define internal void @esan.module_dtor() -; CHECK: call void @__esan_exit(i8* bitcast ({ i8*, i32, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* }* }* @31 to i8*)) Index: llvm/test/Instrumentation/EfficiencySanitizer/struct_field_gep.ll =================================================================== --- llvm/test/Instrumentation/EfficiencySanitizer/struct_field_gep.ll +++ /dev/null @@ -1,41 +0,0 @@ -; Test the complex GetElementPtr instruction handling in the EfficiencySanitizer -; cache fragmentation tool. -; -; RUN: opt < %s -esan -esan-cache-frag -S | FileCheck %s - -; Code from http://llvm.org/docs/LangRef.html#getelementptr-instruction -; struct RT { -; char A; -; int B[10][20]; -; char C; -; }; -; struct ST { -; int X; -; double Y; -; struct RT Z; -; }; -; -; int *foo(struct ST *s) { -; return &s[1].Z.B[5][13]; -; } - -%struct.RT = type { i8, [10 x [20 x i32]], i8 } -%struct.ST = type { i32, double, %struct.RT } - -define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp { -entry: - %arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13 - ret i32* %arrayidx -} - -; CHECK: %0 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.ST$3$13$3$11", i32 0, i32 3) -; CHECK-NEXT: %1 = add i64 %0, 1 -; CHECK-NEXT: store i64 %1, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.ST$3$13$3$11", i32 0, i32 3) -; CHECK-NEXT: %2 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.ST$3$13$3$11", i32 0, i32 2) -; CHECK-NEXT: %3 = add i64 %2, 1 -; CHECK-NEXT: store i64 %3, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.ST$3$13$3$11", i32 0, i32 2) -; CHECK-NEXT: %4 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.RT$3$11$14$11", i32 0, i32 1) -; CHECK-NEXT: %5 = add i64 %4, 1 -; CHECK-NEXT: store i64 %5, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.RT$3$11$14$11", i32 0, i32 1) -; CHECK-NEXT: %arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13 -; CHECK-NEXT: ret i32* %arrayidx Index: llvm/test/Instrumentation/EfficiencySanitizer/struct_field_small.ll =================================================================== --- llvm/test/Instrumentation/EfficiencySanitizer/struct_field_small.ll +++ /dev/null @@ -1,133 +0,0 @@ -; Test basic EfficiencySanitizer struct field count instrumentation with -esan-small-binary -; -; RUN: opt < %s -esan -esan-cache-frag -esan-aux-field-info=false -S | FileCheck %s - -%struct.A = type { i32, i32 } -%union.U = type { double } -%struct.C = type { %struct.anon, %union.anon, [10 x i8] } -%struct.anon = type { i32, i32 } -%union.anon = type { double } - -; CHECK: @0 = private unnamed_addr constant [8 x i8] c"\00", align 1 -; CHECK-NEXT: @1 = private unnamed_addr constant [17 x i8] c"struct.A$2$11$11\00", align 1 -; CHECK-NEXT: @"struct.A$2$11$11" = weak global [3 x i64] zeroinitializer -; CHECK-NEXT: @2 = private unnamed_addr constant [12 x i8] c"union.U$1$3\00", align 1 -; CHECK-NEXT: @"union.U$1$3" = weak global [2 x i64] zeroinitializer -; CHECK-NEXT: @3 = private unnamed_addr constant [20 x i8] c"struct.C$3$14$13$13\00", align 1 -; CHECK-NEXT: @"struct.C$3$14$13$13" = weak global [4 x i64] zeroinitializer -; CHECK-NEXT: @4 = private unnamed_addr constant [20 x i8] c"struct.anon$2$11$11\00", align 1 -; CHECK-NEXT: @"struct.anon$2$11$11" = weak global [3 x i64] zeroinitializer -; CHECK-NEXT: @5 = private unnamed_addr constant [15 x i8] c"union.anon$1$3\00", align 1 -; CHECK-NEXT: @"union.anon$1$3" = weak global [2 x i64] zeroinitializer -; CHECK-NEXT: @6 = internal global [5 x { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* }] [{ i8*, i32, i32, i32*, i32*, i8**, i64*, i64* } { i8* getelementptr inbounds ([17 x i8], [17 x i8]* @1, i32 0, i32 0), i32 8, i32 2, i32* null, i32* null, i8** null, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.A$2$11$11", i32 0, i32 0), i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.A$2$11$11", i32 0, i32 2) }, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* } { i8* getelementptr inbounds ([12 x i8], [12 x i8]* @2, i32 0, i32 0), i32 8, i32 1, i32* null, i32* null, i8** null, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"union.U$1$3", i32 0, i32 0), i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"union.U$1$3", i32 0, i32 1) }, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* } { i8* getelementptr inbounds ([20 x i8], [20 x i8]* @3, i32 0, i32 0), i32 32, i32 3, i32* null, i32* null, i8** null, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 0), i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) }, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* } { i8* getelementptr inbounds ([20 x i8], [20 x i8]* @4, i32 0, i32 0), i32 8, i32 2, i32* null, i32* null, i8** null, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.anon$2$11$11", i32 0, i32 0), i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.anon$2$11$11", i32 0, i32 2) }, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* } { i8* getelementptr inbounds ([15 x i8], [15 x i8]* @5, i32 0, i32 0), i32 8, i32 1, i32* null, i32* null, i8** null, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"union.anon$1$3", i32 0, i32 0), i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"union.anon$1$3", i32 0, i32 1) }] -; CHECK-NEXT: @7 = internal constant { i8*, i32, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* }* } { i8* getelementptr inbounds ([8 x i8], [8 x i8]* @0, i32 0, i32 0), i32 5, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* }* getelementptr inbounds ([5 x { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* }], [5 x { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* }]* @6, i32 0, i32 0) } - -define i32 @main() { -entry: - %a = alloca %struct.A, align 4 - %u = alloca %union.U, align 8 - %c = alloca [2 x %struct.C], align 16 - %k = alloca %struct.A*, align 8 - %x = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 0 - %y = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 1 - %f = bitcast %union.U* %u to float* - %d = bitcast %union.U* %u to double* - %arrayidx = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0 - %cs = getelementptr inbounds %struct.C, %struct.C* %arrayidx, i32 0, i32 0 - %x1 = getelementptr inbounds %struct.anon, %struct.anon* %cs, i32 0, i32 0 - %arrayidx2 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 1 - %cs3 = getelementptr inbounds %struct.C, %struct.C* %arrayidx2, i32 0, i32 0 - %y4 = getelementptr inbounds %struct.anon, %struct.anon* %cs3, i32 0, i32 1 - %arrayidx5 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0 - %cu = getelementptr inbounds %struct.C, %struct.C* %arrayidx5, i32 0, i32 1 - %f6 = bitcast %union.anon* %cu to float* - %arrayidx7 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 1 - %cu8 = getelementptr inbounds %struct.C, %struct.C* %arrayidx7, i32 0, i32 1 - %d9 = bitcast %union.anon* %cu8 to double* - %arrayidx10 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0 - %c11 = getelementptr inbounds %struct.C, %struct.C* %arrayidx10, i32 0, i32 2 - %arrayidx12 = getelementptr inbounds [10 x i8], [10 x i8]* %c11, i64 0, i64 2 - %k1 = load %struct.A*, %struct.A** %k, align 8 - %arrayidx13 = getelementptr inbounds %struct.A, %struct.A* %k1, i64 0 - ret i32 0 -} - -; CHECK: @llvm.global_ctors = {{.*}}@esan.module_ctor -; CHECK: @llvm.global_dtors = {{.*}}@esan.module_dtor - -; CHECK: %a = alloca %struct.A, align 4 -; CHECK-NEXT: %u = alloca %union.U, align 8 -; CHECK-NEXT: %c = alloca [2 x %struct.C], align 16 -; CHECK-NEXT: %k = alloca %struct.A*, align 8 -; CHECK-NEXT: %0 = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.A$2$11$11", i32 0, i32 0) -; CHECK-NEXT: %1 = add i64 %0, 1 -; CHECK-NEXT: store i64 %1, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.A$2$11$11", i32 0, i32 0) -; CHECK-NEXT: %x = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 0 -; CHECK-NEXT: %2 = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.A$2$11$11", i32 0, i32 1) -; CHECK-NEXT: %3 = add i64 %2, 1 -; CHECK-NEXT: store i64 %3, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.A$2$11$11", i32 0, i32 1) -; CHECK-NEXT: %y = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 1 -; CHECK-NEXT: %f = bitcast %union.U* %u to float* -; CHECK-NEXT: %d = bitcast %union.U* %u to double* -; CHECK-NEXT: %4 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %5 = add i64 %4, 1 -; CHECK-NEXT: store i64 %5, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %arrayidx = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0 -; CHECK-NEXT: %6 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 0) -; CHECK-NEXT: %7 = add i64 %6, 1 -; CHECK-NEXT: store i64 %7, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 0) -; CHECK-NEXT: %cs = getelementptr inbounds %struct.C, %struct.C* %arrayidx, i32 0, i32 0 -; CHECK-NEXT: %8 = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.anon$2$11$11", i32 0, i32 0) -; CHECK-NEXT: %9 = add i64 %8, 1 -; CHECK-NEXT: store i64 %9, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.anon$2$11$11", i32 0, i32 0) -; CHECK-NEXT: %x1 = getelementptr inbounds %struct.anon, %struct.anon* %cs, i32 0, i32 0 -; CHECK-NEXT: %10 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %11 = add i64 %10, 1 -; CHECK-NEXT: store i64 %11, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %arrayidx2 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 1 -; CHECK-NEXT: %12 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 0) -; CHECK-NEXT: %13 = add i64 %12, 1 -; CHECK-NEXT: store i64 %13, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 0) -; CHECK-NEXT: %cs3 = getelementptr inbounds %struct.C, %struct.C* %arrayidx2, i32 0, i32 0 -; CHECK-NEXT: %14 = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.anon$2$11$11", i32 0, i32 1) -; CHECK-NEXT: %15 = add i64 %14, 1 -; CHECK-NEXT: store i64 %15, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.anon$2$11$11", i32 0, i32 1) -; CHECK-NEXT: %y4 = getelementptr inbounds %struct.anon, %struct.anon* %cs3, i32 0, i32 1 -; CHECK-NEXT: %16 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %17 = add i64 %16, 1 -; CHECK-NEXT: store i64 %17, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %arrayidx5 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0 -; CHECK-NEXT: %18 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 1) -; CHECK-NEXT: %19 = add i64 %18, 1 -; CHECK-NEXT: store i64 %19, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 1) -; CHECK-NEXT: %cu = getelementptr inbounds %struct.C, %struct.C* %arrayidx5, i32 0, i32 1 -; CHECK-NEXT: %f6 = bitcast %union.anon* %cu to float* -; CHECK-NEXT: %20 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %21 = add i64 %20, 1 -; CHECK-NEXT: store i64 %21, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %arrayidx7 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 1 -; CHECK-NEXT: %22 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 1) -; CHECK-NEXT: %23 = add i64 %22, 1 -; CHECK-NEXT: store i64 %23, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 1) -; CHECK-NEXT: %cu8 = getelementptr inbounds %struct.C, %struct.C* %arrayidx7, i32 0, i32 1 -; CHECK-NEXT: %d9 = bitcast %union.anon* %cu8 to double* -; CHECK-NEXT: %24 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %25 = add i64 %24, 1 -; CHECK-NEXT: store i64 %25, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 3) -; CHECK-NEXT: %arrayidx10 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0 -; CHECK-NEXT: %26 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 2) -; CHECK-NEXT: %27 = add i64 %26, 1 -; CHECK-NEXT: store i64 %27, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @"struct.C$3$14$13$13", i32 0, i32 2) -; CHECK-NEXT: %c11 = getelementptr inbounds %struct.C, %struct.C* %arrayidx10, i32 0, i32 2 -; CHECK-NEXT: %arrayidx12 = getelementptr inbounds [10 x i8], [10 x i8]* %c11, i64 0, i64 2 -; CHECK-NEXT: %k1 = load %struct.A*, %struct.A** %k, align 8 -; CHECK-NEXT: %arrayidx13 = getelementptr inbounds %struct.A, %struct.A* %k1, i64 0 -; CHECK-NEXT: ret i32 0 - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Top-level: - -; CHECK: define internal void @esan.module_ctor() -; CHECK: call void @__esan_init(i32 1, i8* bitcast ({ i8*, i32, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* }* }* @7 to i8*)) -; CHECK: define internal void @esan.module_dtor() -; CHECK: call void @__esan_exit(i8* bitcast ({ i8*, i32, { i8*, i32, i32, i32*, i32*, i8**, i64*, i64* }* }* @7 to i8*)) Index: llvm/test/Instrumentation/EfficiencySanitizer/working_set_basic.ll =================================================================== --- llvm/test/Instrumentation/EfficiencySanitizer/working_set_basic.ll +++ /dev/null @@ -1,275 +0,0 @@ -; Test basic EfficiencySanitizer working set instrumentation. -; -; RUN: opt < %s -esan -esan-working-set -S | FileCheck %s - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Intra-cache-line - -define i8 @aligned1(i8* %a) { -entry: - %tmp1 = load i8, i8* %a, align 1 - ret i8 %tmp1 -; CHECK: @llvm.global_ctors = {{.*}}@esan.module_ctor -; CHECK: %0 = ptrtoint i8* %a to i64 -; CHECK-NEXT: %1 = and i64 %0, 17592186044415 -; CHECK-NEXT: %2 = add i64 %1, 1337006139375616 -; CHECK-NEXT: %3 = lshr i64 %2, 6 -; CHECK-NEXT: %4 = inttoptr i64 %3 to i8* -; CHECK-NEXT: %5 = load i8, i8* %4 -; CHECK-NEXT: %6 = and i8 %5, -127 -; CHECK-NEXT: %7 = icmp ne i8 %6, -127 -; CHECK-NEXT: br i1 %7, label %8, label %11 -; CHECK: %9 = or i8 %5, -127 -; CHECK-NEXT: %10 = inttoptr i64 %3 to i8* -; CHECK-NEXT: store i8 %9, i8* %10 -; CHECK-NEXT: br label %11 -; CHECK: %tmp1 = load i8, i8* %a, align 1 -; CHECK-NEXT: ret i8 %tmp1 -} - -define i16 @aligned2(i16* %a) { -entry: - %tmp1 = load i16, i16* %a, align 2 - ret i16 %tmp1 -; CHECK: %0 = ptrtoint i16* %a to i64 -; CHECK-NEXT: %1 = and i64 %0, 17592186044415 -; CHECK-NEXT: %2 = add i64 %1, 1337006139375616 -; CHECK-NEXT: %3 = lshr i64 %2, 6 -; CHECK-NEXT: %4 = inttoptr i64 %3 to i8* -; CHECK-NEXT: %5 = load i8, i8* %4 -; CHECK-NEXT: %6 = and i8 %5, -127 -; CHECK-NEXT: %7 = icmp ne i8 %6, -127 -; CHECK-NEXT: br i1 %7, label %8, label %11 -; CHECK: %9 = or i8 %5, -127 -; CHECK-NEXT: %10 = inttoptr i64 %3 to i8* -; CHECK-NEXT: store i8 %9, i8* %10 -; CHECK-NEXT: br label %11 -; CHECK: %tmp1 = load i16, i16* %a, align 2 -; CHECK-NEXT: ret i16 %tmp1 -} - -define i32 @aligned4(i32* %a) { -entry: - %tmp1 = load i32, i32* %a, align 4 - ret i32 %tmp1 -; CHECK: %0 = ptrtoint i32* %a to i64 -; CHECK-NEXT: %1 = and i64 %0, 17592186044415 -; CHECK-NEXT: %2 = add i64 %1, 1337006139375616 -; CHECK-NEXT: %3 = lshr i64 %2, 6 -; CHECK-NEXT: %4 = inttoptr i64 %3 to i8* -; CHECK-NEXT: %5 = load i8, i8* %4 -; CHECK-NEXT: %6 = and i8 %5, -127 -; CHECK-NEXT: %7 = icmp ne i8 %6, -127 -; CHECK-NEXT: br i1 %7, label %8, label %11 -; CHECK: %9 = or i8 %5, -127 -; CHECK-NEXT: %10 = inttoptr i64 %3 to i8* -; CHECK-NEXT: store i8 %9, i8* %10 -; CHECK-NEXT: br label %11 -; CHECK: %tmp1 = load i32, i32* %a, align 4 -; CHECK-NEXT: ret i32 %tmp1 -} - -define i64 @aligned8(i64* %a) { -entry: - %tmp1 = load i64, i64* %a, align 8 - ret i64 %tmp1 -; CHECK: %0 = ptrtoint i64* %a to i64 -; CHECK-NEXT: %1 = and i64 %0, 17592186044415 -; CHECK-NEXT: %2 = add i64 %1, 1337006139375616 -; CHECK-NEXT: %3 = lshr i64 %2, 6 -; CHECK-NEXT: %4 = inttoptr i64 %3 to i8* -; CHECK-NEXT: %5 = load i8, i8* %4 -; CHECK-NEXT: %6 = and i8 %5, -127 -; CHECK-NEXT: %7 = icmp ne i8 %6, -127 -; CHECK-NEXT: br i1 %7, label %8, label %11 -; CHECK: %9 = or i8 %5, -127 -; CHECK-NEXT: %10 = inttoptr i64 %3 to i8* -; CHECK-NEXT: store i8 %9, i8* %10 -; CHECK-NEXT: br label %11 -; CHECK: %tmp1 = load i64, i64* %a, align 8 -; CHECK-NEXT: ret i64 %tmp1 -} - -define i128 @aligned16(i128* %a) { -entry: - %tmp1 = load i128, i128* %a, align 16 - ret i128 %tmp1 -; CHECK: %0 = ptrtoint i128* %a to i64 -; CHECK-NEXT: %1 = and i64 %0, 17592186044415 -; CHECK-NEXT: %2 = add i64 %1, 1337006139375616 -; CHECK-NEXT: %3 = lshr i64 %2, 6 -; CHECK-NEXT: %4 = inttoptr i64 %3 to i8* -; CHECK-NEXT: %5 = load i8, i8* %4 -; CHECK-NEXT: %6 = and i8 %5, -127 -; CHECK-NEXT: %7 = icmp ne i8 %6, -127 -; CHECK-NEXT: br i1 %7, label %8, label %11 -; CHECK: %9 = or i8 %5, -127 -; CHECK-NEXT: %10 = inttoptr i64 %3 to i8* -; CHECK-NEXT: store i8 %9, i8* %10 -; CHECK-NEXT: br label %11 -; CHECK: %tmp1 = load i128, i128* %a, align 16 -; CHECK-NEXT: ret i128 %tmp1 -} - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Not guaranteed to be intra-cache-line, but our defaults are to -; assume they are: - -define i16 @unaligned2(i16* %a) { -entry: - %tmp1 = load i16, i16* %a, align 1 - ret i16 %tmp1 -; CHECK: %0 = ptrtoint i16* %a to i64 -; CHECK-NEXT: %1 = and i64 %0, 17592186044415 -; CHECK-NEXT: %2 = add i64 %1, 1337006139375616 -; CHECK-NEXT: %3 = lshr i64 %2, 6 -; CHECK-NEXT: %4 = inttoptr i64 %3 to i8* -; CHECK-NEXT: %5 = load i8, i8* %4 -; CHECK-NEXT: %6 = and i8 %5, -127 -; CHECK-NEXT: %7 = icmp ne i8 %6, -127 -; CHECK-NEXT: br i1 %7, label %8, label %11 -; CHECK: %9 = or i8 %5, -127 -; CHECK-NEXT: %10 = inttoptr i64 %3 to i8* -; CHECK-NEXT: store i8 %9, i8* %10 -; CHECK-NEXT: br label %11 -; CHECK: %tmp1 = load i16, i16* %a, align 1 -; CHECK-NEXT: ret i16 %tmp1 -} - -define i32 @unaligned4(i32* %a) { -entry: - %tmp1 = load i32, i32* %a, align 2 - ret i32 %tmp1 -; CHECK: %0 = ptrtoint i32* %a to i64 -; CHECK-NEXT: %1 = and i64 %0, 17592186044415 -; CHECK-NEXT: %2 = add i64 %1, 1337006139375616 -; CHECK-NEXT: %3 = lshr i64 %2, 6 -; CHECK-NEXT: %4 = inttoptr i64 %3 to i8* -; CHECK-NEXT: %5 = load i8, i8* %4 -; CHECK-NEXT: %6 = and i8 %5, -127 -; CHECK-NEXT: %7 = icmp ne i8 %6, -127 -; CHECK-NEXT: br i1 %7, label %8, label %11 -; CHECK: %9 = or i8 %5, -127 -; CHECK-NEXT: %10 = inttoptr i64 %3 to i8* -; CHECK-NEXT: store i8 %9, i8* %10 -; CHECK-NEXT: br label %11 -; CHECK: %tmp1 = load i32, i32* %a, align 2 -; CHECK-NEXT: ret i32 %tmp1 -} - -define i64 @unaligned8(i64* %a) { -entry: - %tmp1 = load i64, i64* %a, align 4 - ret i64 %tmp1 -; CHECK: %0 = ptrtoint i64* %a to i64 -; CHECK-NEXT: %1 = and i64 %0, 17592186044415 -; CHECK-NEXT: %2 = add i64 %1, 1337006139375616 -; CHECK-NEXT: %3 = lshr i64 %2, 6 -; CHECK-NEXT: %4 = inttoptr i64 %3 to i8* -; CHECK-NEXT: %5 = load i8, i8* %4 -; CHECK-NEXT: %6 = and i8 %5, -127 -; CHECK-NEXT: %7 = icmp ne i8 %6, -127 -; CHECK-NEXT: br i1 %7, label %8, label %11 -; CHECK: %9 = or i8 %5, -127 -; CHECK-NEXT: %10 = inttoptr i64 %3 to i8* -; CHECK-NEXT: store i8 %9, i8* %10 -; CHECK-NEXT: br label %11 -; CHECK: %tmp1 = load i64, i64* %a, align 4 -; CHECK-NEXT: ret i64 %tmp1 -} - -define i128 @unaligned16(i128* %a) { -entry: - %tmp1 = load i128, i128* %a, align 8 - ret i128 %tmp1 -; CHECK: %0 = ptrtoint i128* %a to i64 -; CHECK-NEXT: %1 = and i64 %0, 17592186044415 -; CHECK-NEXT: %2 = add i64 %1, 1337006139375616 -; CHECK-NEXT: %3 = lshr i64 %2, 6 -; CHECK-NEXT: %4 = inttoptr i64 %3 to i8* -; CHECK-NEXT: %5 = load i8, i8* %4 -; CHECK-NEXT: %6 = and i8 %5, -127 -; CHECK-NEXT: %7 = icmp ne i8 %6, -127 -; CHECK-NEXT: br i1 %7, label %8, label %11 -; CHECK: %9 = or i8 %5, -127 -; CHECK-NEXT: %10 = inttoptr i64 %3 to i8* -; CHECK-NEXT: store i8 %9, i8* %10 -; CHECK-NEXT: br label %11 -; CHECK: %tmp1 = load i128, i128* %a, align 8 -; CHECK-NEXT: ret i128 %tmp1 -} - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Ensure that esan converts intrinsics to calls: - -declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) -declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) -declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i1) - -define void @memCpyTest(i8* nocapture %x, i8* nocapture %y) { -entry: - tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %x, i8* align 4 %y, i64 16, i1 false) - ret void -; CHECK: define void @memCpyTest -; CHECK: call i8* @memcpy -; CHECK: ret void -} - -define void @memMoveTest(i8* nocapture %x, i8* nocapture %y) { -entry: - tail call void @llvm.memmove.p0i8.p0i8.i64(i8* align 4 %x, i8* align 4 %y, i64 16, i1 false) - ret void -; CHECK: define void @memMoveTest -; CHECK: call i8* @memmove -; CHECK: ret void -} - -define void @memSetTest(i8* nocapture %x) { -entry: - tail call void @llvm.memset.p0i8.i64(i8* align 4 %x, i8 77, i64 16, i1 false) - ret void -; CHECK: define void @memSetTest -; CHECK: call i8* @memset -; CHECK: ret void -} - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Ensure that esan doesn't convert element atomic memory intrinsics to -; calls. - -declare void @llvm.memset.element.unordered.atomic.p0i8.i64(i8* nocapture writeonly, i8, i64, i32) nounwind -declare void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32) nounwind -declare void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32) nounwind - -define void @elementAtomic_memCpyTest(i8* nocapture %x, i8* nocapture %y) { - ; CHECK-LABEL: elementAtomic_memCpyTest - ; CHECK-NEXT: tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %x, i8* align 1 %y, i64 16, i32 1) - ; CHECK-NEXT: ret void - tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %x, i8* align 1 %y, i64 16, i32 1) - ret void -} - -define void @elementAtomic_memMoveTest(i8* nocapture %x, i8* nocapture %y) { - ; CHECK-LABEL: elementAtomic_memMoveTest - ; CHECK-NEXT: tail call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %x, i8* align 1 %y, i64 16, i32 1) - ; CHECK-NEXT: ret void - tail call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %x, i8* align 1 %y, i64 16, i32 1) - ret void -} - -define void @elementAtomic_memSetTest(i8* nocapture %x) { - ; CHECK-LABEL: elementAtomic_memSetTest - ; CHECK-NEXT: tail call void @llvm.memset.element.unordered.atomic.p0i8.i64(i8* align 1 %x, i8 77, i64 16, i32 1) - ; CHECK-NEXT: ret void - tail call void @llvm.memset.element.unordered.atomic.p0i8.i64(i8* align 1 %x, i8 77, i64 16, i32 1) - ret void -} - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Top-level: - -; CHECK: define internal void @esan.module_ctor() -; CHECK: call void @__esan_init(i32 2, i8* null) -; CHECK: define internal void @esan.module_dtor() -; CHECK: call void @__esan_exit(i8* null) Index: llvm/test/Instrumentation/EfficiencySanitizer/working_set_slow.ll =================================================================== --- llvm/test/Instrumentation/EfficiencySanitizer/working_set_slow.ll +++ /dev/null @@ -1,291 +0,0 @@ -; Test basic EfficiencySanitizer slowpath instrumentation. -; -; RUN: opt < %s -esan -esan-working-set -esan-instrument-fastpath=false -S | FileCheck %s - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Aligned loads: - -define i8 @loadAligned1(i8* %a) { -entry: - %tmp1 = load i8, i8* %a, align 1 - ret i8 %tmp1 -; CHECK: @llvm.global_ctors = {{.*}}@esan.module_ctor -; CHECK: call void @__esan_aligned_load1(i8* %a) -; CHECK-NEXT: %tmp1 = load i8, i8* %a, align 1 -; CHECK-NEXT: ret i8 %tmp1 -} - -define i16 @loadAligned2(i16* %a) { -entry: - %tmp1 = load i16, i16* %a, align 2 - ret i16 %tmp1 -; CHECK: %0 = bitcast i16* %a to i8* -; CHECK-NEXT: call void @__esan_aligned_load2(i8* %0) -; CHECK-NEXT: %tmp1 = load i16, i16* %a, align 2 -; CHECK-NEXT: ret i16 %tmp1 -} - -define i32 @loadAligned4(i32* %a) { -entry: - %tmp1 = load i32, i32* %a, align 4 - ret i32 %tmp1 -; CHECK: %0 = bitcast i32* %a to i8* -; CHECK-NEXT: call void @__esan_aligned_load4(i8* %0) -; CHECK-NEXT: %tmp1 = load i32, i32* %a, align 4 -; CHECK-NEXT: ret i32 %tmp1 -} - -define i64 @loadAligned8(i64* %a) { -entry: - %tmp1 = load i64, i64* %a, align 8 - ret i64 %tmp1 -; CHECK: %0 = bitcast i64* %a to i8* -; CHECK-NEXT: call void @__esan_aligned_load8(i8* %0) -; CHECK-NEXT: %tmp1 = load i64, i64* %a, align 8 -; CHECK-NEXT: ret i64 %tmp1 -} - -define i128 @loadAligned16(i128* %a) { -entry: - %tmp1 = load i128, i128* %a, align 16 - ret i128 %tmp1 -; CHECK: %0 = bitcast i128* %a to i8* -; CHECK-NEXT: call void @__esan_aligned_load16(i8* %0) -; CHECK-NEXT: %tmp1 = load i128, i128* %a, align 16 -; CHECK-NEXT: ret i128 %tmp1 -} - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Aligned stores: - -define void @storeAligned1(i8* %a) { -entry: - store i8 1, i8* %a, align 1 - ret void -; CHECK: call void @__esan_aligned_store1(i8* %a) -; CHECK-NEXT: store i8 1, i8* %a, align 1 -; CHECK-NEXT: ret void -} - -define void @storeAligned2(i16* %a) { -entry: - store i16 1, i16* %a, align 2 - ret void -; CHECK: %0 = bitcast i16* %a to i8* -; CHECK-NEXT: call void @__esan_aligned_store2(i8* %0) -; CHECK-NEXT: store i16 1, i16* %a, align 2 -; CHECK-NEXT: ret void -} - -define void @storeAligned4(i32* %a) { -entry: - store i32 1, i32* %a, align 4 - ret void -; CHECK: %0 = bitcast i32* %a to i8* -; CHECK-NEXT: call void @__esan_aligned_store4(i8* %0) -; CHECK-NEXT: store i32 1, i32* %a, align 4 -; CHECK-NEXT: ret void -} - -define void @storeAligned8(i64* %a) { -entry: - store i64 1, i64* %a, align 8 - ret void -; CHECK: %0 = bitcast i64* %a to i8* -; CHECK-NEXT: call void @__esan_aligned_store8(i8* %0) -; CHECK-NEXT: store i64 1, i64* %a, align 8 -; CHECK-NEXT: ret void -} - -define void @storeAligned16(i128* %a) { -entry: - store i128 1, i128* %a, align 16 - ret void -; CHECK: %0 = bitcast i128* %a to i8* -; CHECK-NEXT: call void @__esan_aligned_store16(i8* %0) -; CHECK-NEXT: store i128 1, i128* %a, align 16 -; CHECK-NEXT: ret void -} - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Unaligned loads: - -define i16 @loadUnaligned2(i16* %a) { -entry: - %tmp1 = load i16, i16* %a, align 1 - ret i16 %tmp1 -; CHECK: %0 = bitcast i16* %a to i8* -; CHECK-NEXT: call void @__esan_unaligned_load2(i8* %0) -; CHECK-NEXT: %tmp1 = load i16, i16* %a, align 1 -; CHECK-NEXT: ret i16 %tmp1 -} - -define i32 @loadUnaligned4(i32* %a) { -entry: - %tmp1 = load i32, i32* %a, align 1 - ret i32 %tmp1 -; CHECK: %0 = bitcast i32* %a to i8* -; CHECK-NEXT: call void @__esan_unaligned_load4(i8* %0) -; CHECK-NEXT: %tmp1 = load i32, i32* %a, align 1 -; CHECK-NEXT: ret i32 %tmp1 -} - -define i64 @loadUnaligned8(i64* %a) { -entry: - %tmp1 = load i64, i64* %a, align 1 - ret i64 %tmp1 -; CHECK: %0 = bitcast i64* %a to i8* -; CHECK-NEXT: call void @__esan_unaligned_load8(i8* %0) -; CHECK-NEXT: %tmp1 = load i64, i64* %a, align 1 -; CHECK-NEXT: ret i64 %tmp1 -} - -define i128 @loadUnaligned16(i128* %a) { -entry: - %tmp1 = load i128, i128* %a, align 1 - ret i128 %tmp1 -; CHECK: %0 = bitcast i128* %a to i8* -; CHECK-NEXT: call void @__esan_unaligned_load16(i8* %0) -; CHECK-NEXT: %tmp1 = load i128, i128* %a, align 1 -; CHECK-NEXT: ret i128 %tmp1 -} - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Unaligned stores: - -define void @storeUnaligned2(i16* %a) { -entry: - store i16 1, i16* %a, align 1 - ret void -; CHECK: %0 = bitcast i16* %a to i8* -; CHECK-NEXT: call void @__esan_unaligned_store2(i8* %0) -; CHECK-NEXT: store i16 1, i16* %a, align 1 -; CHECK-NEXT: ret void -} - -define void @storeUnaligned4(i32* %a) { -entry: - store i32 1, i32* %a, align 1 - ret void -; CHECK: %0 = bitcast i32* %a to i8* -; CHECK-NEXT: call void @__esan_unaligned_store4(i8* %0) -; CHECK-NEXT: store i32 1, i32* %a, align 1 -; CHECK-NEXT: ret void -} - -define void @storeUnaligned8(i64* %a) { -entry: - store i64 1, i64* %a, align 1 - ret void -; CHECK: %0 = bitcast i64* %a to i8* -; CHECK-NEXT: call void @__esan_unaligned_store8(i8* %0) -; CHECK-NEXT: store i64 1, i64* %a, align 1 -; CHECK-NEXT: ret void -} - -define void @storeUnaligned16(i128* %a) { -entry: - store i128 1, i128* %a, align 1 - ret void -; CHECK: %0 = bitcast i128* %a to i8* -; CHECK-NEXT: call void @__esan_unaligned_store16(i8* %0) -; CHECK-NEXT: store i128 1, i128* %a, align 1 -; CHECK-NEXT: ret void -} - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Unusual loads and stores: - -define x86_fp80 @loadUnalignedFP(x86_fp80* %a) { -entry: - %tmp1 = load x86_fp80, x86_fp80* %a, align 1 - ret x86_fp80 %tmp1 -; CHECK: %0 = bitcast x86_fp80* %a to i8* -; CHECK-NEXT: call void @__esan_unaligned_loadN(i8* %0, i64 10) -; CHECK-NEXT: %tmp1 = load x86_fp80, x86_fp80* %a, align 1 -; CHECK-NEXT: ret x86_fp80 %tmp1 -} - -define void @storeUnalignedFP(x86_fp80* %a) { -entry: - store x86_fp80 0xK00000000000000000000, x86_fp80* %a, align 1 - ret void -; CHECK: %0 = bitcast x86_fp80* %a to i8* -; CHECK-NEXT: call void @__esan_unaligned_storeN(i8* %0, i64 10) -; CHECK-NEXT: store x86_fp80 0xK00000000000000000000, x86_fp80* %a, align 1 -; CHECK-NEXT: ret void -} - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Ensure that esan converts memcpy intrinsics to calls: - -declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) -declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) -declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i1) - -define void @memCpyTest(i8* nocapture %x, i8* nocapture %y) { -entry: - tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %x, i8* align 4 %y, i64 16, i1 false) - ret void -; CHECK: define void @memCpyTest -; CHECK: call i8* @memcpy -; CHECK: ret void -} - -define void @memMoveTest(i8* nocapture %x, i8* nocapture %y) { -entry: - tail call void @llvm.memmove.p0i8.p0i8.i64(i8* align 4 %x, i8* align 4 %y, i64 16, i1 false) - ret void -; CHECK: define void @memMoveTest -; CHECK: call i8* @memmove -; CHECK: ret void -} - -define void @memSetTest(i8* nocapture %x) { -entry: - tail call void @llvm.memset.p0i8.i64(i8* align 4 %x, i8 77, i64 16, i1 false) - ret void -; CHECK: define void @memSetTest -; CHECK: call i8* @memset -; CHECK: ret void -} - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Ensure that esan doesn't convert element atomic memory intrinsics to -; calls. - -declare void @llvm.memset.element.unordered.atomic.p0i8.i64(i8* nocapture writeonly, i8, i64, i32) nounwind -declare void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32) nounwind -declare void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32) nounwind - -define void @elementAtomic_memCpyTest(i8* nocapture %x, i8* nocapture %y) { - ; CHECK-LABEL: elementAtomic_memCpyTest - ; CHECK-NEXT: tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %x, i8* align 1 %y, i64 16, i32 1) - ; CHECK-NEXT: ret void - tail call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %x, i8* align 1 %y, i64 16, i32 1) - ret void -} - -define void @elementAtomic_memMoveTest(i8* nocapture %x, i8* nocapture %y) { - ; CHECK-LABEL: elementAtomic_memMoveTest - ; CHECK-NEXT: tail call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %x, i8* align 1 %y, i64 16, i32 1) - ; CHECK-NEXT: ret void - tail call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %x, i8* align 1 %y, i64 16, i32 1) - ret void -} - -define void @elementAtomic_memSetTest(i8* nocapture %x) { - ; CHECK-LABEL: elementAtomic_memSetTest - ; CHECK-NEXT: tail call void @llvm.memset.element.unordered.atomic.p0i8.i64(i8* align 1 %x, i8 77, i64 16, i32 1) - ; CHECK-NEXT: ret void - tail call void @llvm.memset.element.unordered.atomic.p0i8.i64(i8* align 1 %x, i8 77, i64 16, i32 1) - ret void -} - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Top-level: - -; CHECK: define internal void @esan.module_ctor() -; CHECK: call void @__esan_init(i32 2, i8* null) -; CHECK: define internal void @esan.module_dtor() -; CHECK: call void @__esan_exit(i8* null) Index: llvm/test/Instrumentation/EfficiencySanitizer/working_set_strict.ll =================================================================== --- llvm/test/Instrumentation/EfficiencySanitizer/working_set_strict.ll +++ /dev/null @@ -1,156 +0,0 @@ -; Test EfficiencySanitizer working set instrumentation without aggressive -; optimization flags. -; -; RUN: opt < %s -esan -esan-working-set -esan-assume-intra-cache-line=0 -S | FileCheck %s - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Intra-cache-line - -define i8 @aligned1(i8* %a) { -entry: - %tmp1 = load i8, i8* %a, align 1 - ret i8 %tmp1 -; CHECK: @llvm.global_ctors = {{.*}}@esan.module_ctor -; CHECK: %0 = ptrtoint i8* %a to i64 -; CHECK-NEXT: %1 = and i64 %0, 17592186044415 -; CHECK-NEXT: %2 = add i64 %1, 1337006139375616 -; CHECK-NEXT: %3 = lshr i64 %2, 6 -; CHECK-NEXT: %4 = inttoptr i64 %3 to i8* -; CHECK-NEXT: %5 = load i8, i8* %4 -; CHECK-NEXT: %6 = and i8 %5, -127 -; CHECK-NEXT: %7 = icmp ne i8 %6, -127 -; CHECK-NEXT: br i1 %7, label %8, label %11 -; CHECK: %9 = or i8 %5, -127 -; CHECK-NEXT: %10 = inttoptr i64 %3 to i8* -; CHECK-NEXT: store i8 %9, i8* %10 -; CHECK-NEXT: br label %11 -; CHECK: %tmp1 = load i8, i8* %a, align 1 -; CHECK-NEXT: ret i8 %tmp1 -} - -define i16 @aligned2(i16* %a) { -entry: - %tmp1 = load i16, i16* %a, align 2 - ret i16 %tmp1 -; CHECK: %0 = ptrtoint i16* %a to i64 -; CHECK-NEXT: %1 = and i64 %0, 17592186044415 -; CHECK-NEXT: %2 = add i64 %1, 1337006139375616 -; CHECK-NEXT: %3 = lshr i64 %2, 6 -; CHECK-NEXT: %4 = inttoptr i64 %3 to i8* -; CHECK-NEXT: %5 = load i8, i8* %4 -; CHECK-NEXT: %6 = and i8 %5, -127 -; CHECK-NEXT: %7 = icmp ne i8 %6, -127 -; CHECK-NEXT: br i1 %7, label %8, label %11 -; CHECK: %9 = or i8 %5, -127 -; CHECK-NEXT: %10 = inttoptr i64 %3 to i8* -; CHECK-NEXT: store i8 %9, i8* %10 -; CHECK-NEXT: br label %11 -; CHECK: %tmp1 = load i16, i16* %a, align 2 -; CHECK-NEXT: ret i16 %tmp1 -} - -define i32 @aligned4(i32* %a) { -entry: - %tmp1 = load i32, i32* %a, align 4 - ret i32 %tmp1 -; CHECK: %0 = ptrtoint i32* %a to i64 -; CHECK-NEXT: %1 = and i64 %0, 17592186044415 -; CHECK-NEXT: %2 = add i64 %1, 1337006139375616 -; CHECK-NEXT: %3 = lshr i64 %2, 6 -; CHECK-NEXT: %4 = inttoptr i64 %3 to i8* -; CHECK-NEXT: %5 = load i8, i8* %4 -; CHECK-NEXT: %6 = and i8 %5, -127 -; CHECK-NEXT: %7 = icmp ne i8 %6, -127 -; CHECK-NEXT: br i1 %7, label %8, label %11 -; CHECK: %9 = or i8 %5, -127 -; CHECK-NEXT: %10 = inttoptr i64 %3 to i8* -; CHECK-NEXT: store i8 %9, i8* %10 -; CHECK-NEXT: br label %11 -; CHECK: %tmp1 = load i32, i32* %a, align 4 -; CHECK-NEXT: ret i32 %tmp1 -} - -define i64 @aligned8(i64* %a) { -entry: - %tmp1 = load i64, i64* %a, align 8 - ret i64 %tmp1 -; CHECK: %0 = ptrtoint i64* %a to i64 -; CHECK-NEXT: %1 = and i64 %0, 17592186044415 -; CHECK-NEXT: %2 = add i64 %1, 1337006139375616 -; CHECK-NEXT: %3 = lshr i64 %2, 6 -; CHECK-NEXT: %4 = inttoptr i64 %3 to i8* -; CHECK-NEXT: %5 = load i8, i8* %4 -; CHECK-NEXT: %6 = and i8 %5, -127 -; CHECK-NEXT: %7 = icmp ne i8 %6, -127 -; CHECK-NEXT: br i1 %7, label %8, label %11 -; CHECK: %9 = or i8 %5, -127 -; CHECK-NEXT: %10 = inttoptr i64 %3 to i8* -; CHECK-NEXT: store i8 %9, i8* %10 -; CHECK-NEXT: br label %11 -; CHECK: %tmp1 = load i64, i64* %a, align 8 -; CHECK-NEXT: ret i64 %tmp1 -} - -define i128 @aligned16(i128* %a) { -entry: - %tmp1 = load i128, i128* %a, align 16 - ret i128 %tmp1 -; CHECK: %0 = ptrtoint i128* %a to i64 -; CHECK-NEXT: %1 = and i64 %0, 17592186044415 -; CHECK-NEXT: %2 = add i64 %1, 1337006139375616 -; CHECK-NEXT: %3 = lshr i64 %2, 6 -; CHECK-NEXT: %4 = inttoptr i64 %3 to i8* -; CHECK-NEXT: %5 = load i8, i8* %4 -; CHECK-NEXT: %6 = and i8 %5, -127 -; CHECK-NEXT: %7 = icmp ne i8 %6, -127 -; CHECK-NEXT: br i1 %7, label %8, label %11 -; CHECK: %9 = or i8 %5, -127 -; CHECK-NEXT: %10 = inttoptr i64 %3 to i8* -; CHECK-NEXT: store i8 %9, i8* %10 -; CHECK-NEXT: br label %11 -; CHECK: %tmp1 = load i128, i128* %a, align 16 -; CHECK-NEXT: ret i128 %tmp1 -} - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Not guaranteed to be intra-cache-line - -define i16 @unaligned2(i16* %a) { -entry: - %tmp1 = load i16, i16* %a, align 1 - ret i16 %tmp1 -; CHECK: %0 = bitcast i16* %a to i8* -; CHECK-NEXT: call void @__esan_unaligned_load2(i8* %0) -; CHECK-NEXT: %tmp1 = load i16, i16* %a, align 1 -; CHECK-NEXT: ret i16 %tmp1 -} - -define i32 @unaligned4(i32* %a) { -entry: - %tmp1 = load i32, i32* %a, align 2 - ret i32 %tmp1 -; CHECK: %0 = bitcast i32* %a to i8* -; CHECK-NEXT: call void @__esan_unaligned_load4(i8* %0) -; CHECK-NEXT: %tmp1 = load i32, i32* %a, align 2 -; CHECK-NEXT: ret i32 %tmp1 -} - -define i64 @unaligned8(i64* %a) { -entry: - %tmp1 = load i64, i64* %a, align 4 - ret i64 %tmp1 -; CHECK: %0 = bitcast i64* %a to i8* -; CHECK-NEXT: call void @__esan_unaligned_load8(i8* %0) -; CHECK-NEXT: %tmp1 = load i64, i64* %a, align 4 -; CHECK-NEXT: ret i64 %tmp1 -} - -define i128 @unaligned16(i128* %a) { -entry: - %tmp1 = load i128, i128* %a, align 8 - ret i128 %tmp1 -; CHECK: %0 = bitcast i128* %a to i8* -; CHECK-NEXT: call void @__esan_unaligned_load16(i8* %0) -; CHECK-NEXT: %tmp1 = load i128, i128* %a, align 8 -; CHECK-NEXT: ret i128 %tmp1 -} Index: llvm/utils/gn/secondary/compiler-rt/include/BUILD.gn =================================================================== --- llvm/utils/gn/secondary/compiler-rt/include/BUILD.gn +++ llvm/utils/gn/secondary/compiler-rt/include/BUILD.gn @@ -7,7 +7,6 @@ "sanitizer/common_interface_defs.h", "sanitizer/coverage_interface.h", "sanitizer/dfsan_interface.h", - "sanitizer/esan_interface.h", "sanitizer/hwasan_interface.h", "sanitizer/linux_syscall_hooks.h", "sanitizer/lsan_interface.h", Index: llvm/utils/gn/secondary/llvm/lib/Transforms/Instrumentation/BUILD.gn =================================================================== --- llvm/utils/gn/secondary/llvm/lib/Transforms/Instrumentation/BUILD.gn +++ llvm/utils/gn/secondary/llvm/lib/Transforms/Instrumentation/BUILD.gn @@ -14,7 +14,6 @@ "CGProfile.cpp", "ControlHeightReduction.cpp", "DataFlowSanitizer.cpp", - "EfficiencySanitizer.cpp", "GCOVProfiling.cpp", "HWAddressSanitizer.cpp", "IndirectCallPromotion.cpp",