diff --git a/include/llvm/Transforms/Instrumentation.h b/include/llvm/Transforms/Instrumentation.h index 9517fdf669e..fdaa388210d 100644 --- a/include/llvm/Transforms/Instrumentation.h +++ b/include/llvm/Transforms/Instrumentation.h @@ -137,7 +137,7 @@ struct SanitizerCoverageOptions { SanitizerCoverageOptions() : CoverageType(SCK_None), IndirectCalls(false), TraceBB(false), TraceCmp(false), TraceDiv(false), TraceGep(false), - Use8bitCounters(false), TracePC(false) {} + Use8bitCounters(false), TracePC(false), TracePCGuard(false) {} enum Type { SCK_None = 0, @@ -152,6 +152,7 @@ struct SanitizerCoverageOptions { bool TraceGep; bool Use8bitCounters; bool TracePC; + bool TracePCGuard; }; // Insert SanitizerCoverage instrumentation. diff --git a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp index 5a70598329a..63b2a6d1e0f 100644 --- a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -78,6 +78,12 @@ static const char *const SanCovTraceSwitchName = "__sanitizer_cov_trace_switch"; static const char *const SanCovModuleCtorName = "sancov.module_ctor"; static const uint64_t SanCtorAndDtorPriority = 2; +static const char *const SanCovTracePCGuardSection = "__sancov_guards"; +static const char *const SanCovTracePCGuardName = + "__sanitizer_cov_trace_pc_guard"; +static const char *const SanCovTracePCGuardInitName = + "__sanitizer_cov_trace_pc_guard_init"; + static cl::opt ClCoverageLevel( "sanitizer-coverage-level", cl::desc("Sanitizer Coverage. 0: none, 1: entry block, 2: all blocks, " @@ -101,6 +107,10 @@ static cl::opt ClExperimentalTracePC("sanitizer-coverage-trace-pc", cl::desc("Experimental pc tracing"), cl::Hidden, cl::init(false)); +static cl::opt ClTracePCGuard("sanitizer-coverage-trace-pc-guard", + cl::desc("pc tracing with a guard"), + cl::Hidden, cl::init(false)); + static cl::opt ClCMPTracing("sanitizer-coverage-trace-compares", cl::desc("Tracing of CMP and similar instructions"), @@ -165,6 +175,7 @@ SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) { Options.TraceGep |= ClGEPTracing; Options.Use8bitCounters |= ClUse8bitCounters; Options.TracePC |= ClExperimentalTracePC; + Options.TracePCGuard |= ClTracePCGuard; return Options; } @@ -206,7 +217,7 @@ private: Function *SanCovFunction; Function *SanCovWithCheckFunction; Function *SanCovIndirCallFunction, *SanCovTracePCIndir; - Function *SanCovTraceEnter, *SanCovTraceBB, *SanCovTracePC; + Function *SanCovTraceEnter, *SanCovTraceBB, *SanCovTracePC, *SanCovTracePCGuard; Function *SanCovTraceCmpFunction[4]; Function *SanCovTraceDivFunction[2]; Function *SanCovTraceGepFunction; @@ -281,6 +292,8 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { SanCovTracePC = checkSanitizerInterfaceFunction( M.getOrInsertFunction(SanCovTracePCName, VoidTy, nullptr)); + SanCovTracePCGuard = checkSanitizerInterfaceFunction(M.getOrInsertFunction( + SanCovTracePCGuardName, VoidTy, IRB.getInt8PtrTy(), nullptr)); SanCovTraceEnter = checkSanitizerInterfaceFunction( M.getOrInsertFunction(SanCovTraceEnterName, VoidTy, Int32PtrTy, nullptr)); SanCovTraceBB = checkSanitizerInterfaceFunction( @@ -336,8 +349,23 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { GlobalVariable *ModuleName = new GlobalVariable(M, ModNameStrConst->getType(), true, GlobalValue::PrivateLinkage, ModNameStrConst); + if (Options.TracePCGuard) { + Function *CtorFunc; + std::string SectionName(SanCovTracePCGuardSection); + auto Start = + new GlobalVariable(M, Int8PtrTy, false, GlobalVariable::ExternalLinkage, + nullptr, "__start_" + SectionName); + auto Stop = + new GlobalVariable(M, Int8PtrTy, false, GlobalVariable::ExternalLinkage, + nullptr, "__stop_" + SectionName); + std::tie(CtorFunc, std::ignore) = createSanitizerCtorAndInitFunctions( + M, SanCovModuleCtorName, SanCovTracePCGuardInitName, + {Int8PtrTy, Int8PtrTy}, {IRB.CreatePointerCast(Start, Int8PtrTy), + IRB.CreatePointerCast(Stop, Int8PtrTy)}); - if (!Options.TracePC) { + appendToGlobalCtors(M, CtorFunc, SanCtorAndDtorPriority); + + } else if (!Options.TracePC) { Function *CtorFunc; std::tie(CtorFunc, std::ignore) = createSanitizerCtorAndInitFunctions( M, SanCovModuleCtorName, SanCovModuleInitName, @@ -395,6 +423,8 @@ bool SanitizerCoverageModule::runOnFunction(Function &F) { return false; if (F.getName().find(".module_ctor") != std::string::npos) return false; // Should not instrument sanitizer init functions. + if (F.getName().startswith("__sanitizer_")) + return false; // Don't instrument __sanitizer_* callbacks. // Don't instrument functions using SEH for now. Splitting basic blocks like // we do for coverage breaks WinEHPrepare. // FIXME: Remove this when SEH no longer uses landingpad pattern matching. @@ -631,6 +661,26 @@ void SanitizerCoverageModule::InjectCoverageAtBlock(Function &F, BasicBlock &BB, if (Options.TracePC) { IRB.CreateCall(SanCovTracePC); // gets the PC using GET_CALLER_PC. IRB.CreateCall(EmptyAsm, {}); // Avoids callback merge. + } else if (Options.TracePCGuard) { + auto GuardVar = new GlobalVariable(*F.getParent(), IRB.getInt8Ty(), false, + GlobalVariable::LinkOnceODRLinkage, + Constant::getNullValue(IRB.getInt8Ty()), + "__sancov_guard." + F.getName()); + // TODO: add debug into to GuardVar. + GuardVar->setSection(SanCovTracePCGuardSection); + auto GuardPtr = IRB.CreatePointerCast(GuardVar, IRB.getInt8PtrTy()); + auto GuardLoad = IRB.CreateLoad(GuardPtr); + GuardLoad->setAtomic(AtomicOrdering::Monotonic); + GuardLoad->setAlignment(1); + SetNoSanitizeMetadata(GuardLoad); // Don't instrument with e.g. asan. + auto Cmp = IRB.CreateICmpNE( + Constant::getAllOnesValue(GuardLoad->getType()), GuardLoad); + auto Ins = SplitBlockAndInsertIfThen( + Cmp, &*IP, false, MDBuilder(*C).createBranchWeights(1, 100000)); + IRB.SetCurrentDebugLocation(EntryLoc); + IRB.SetInsertPoint(Ins); + IRB.CreateCall(SanCovTracePCGuard, GuardPtr); + IRB.CreateCall(EmptyAsm, {}); // Avoids callback merge. } else if (Options.TraceBB) { IRB.CreateCall(IsEntryBB ? SanCovTraceEnter : SanCovTraceBB, GuardP); } else if (UseCalls) { diff --git a/test/Instrumentation/SanitizerCoverage/tracing.ll b/test/Instrumentation/SanitizerCoverage/tracing.ll index a5c3609530f..5b6a17bd9e7 100644 --- a/test/Instrumentation/SanitizerCoverage/tracing.ll +++ b/test/Instrumentation/SanitizerCoverage/tracing.ll @@ -2,6 +2,7 @@ ; RUN: opt < %s -sancov -sanitizer-coverage-level=2 -sanitizer-coverage-experimental-tracing -S | FileCheck %s --check-prefix=CHECK1 ; RUN: opt < %s -sancov -sanitizer-coverage-level=3 -sanitizer-coverage-experimental-tracing -S | FileCheck %s --check-prefix=CHECK3 ; RUN: opt < %s -sancov -sanitizer-coverage-level=3 -sanitizer-coverage-trace-pc -S | FileCheck %s --check-prefix=CHECK_PC +; RUN: opt < %s -sancov -sanitizer-coverage-level=3 -sanitizer-coverage-trace-pc-guard -S | FileCheck %s --check-prefix=CHECK_PC_GUARD 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" @@ -38,3 +39,11 @@ entry: ; CHECK_PC-NOT: call void @__sanitizer_cov_trace_pc ; CHECK_PC: ret void ; CHECK_PC-NOT: call void @__sanitizer_cov_module_init + +; CHECK_PC_GUARD-LABEL: define void @foo +; CHECK_PC_GUARD: call void @__sanitizer_cov_trace_pc_guard +; CHECK_PC_GUARD: call void @__sanitizer_cov_trace_pc_guard +; CHECK_PC_GUARD: call void @__sanitizer_cov_trace_pc_guard +; CHECK_PC_GUARD-NOT: call void @__sanitizer_cov_trace_pc +; CHECK_PC_GUARD: ret void +; CHECK_PC_GUARD: call void @__sanitizer_cov_trace_pc_guard_init(i8* bitcast (i8** @__start___sancov_guards to i8*), i8* bitcast (i8** @__stop___sancov_guards to i8*))