From a0e2bc22aa3c7dbb9d45477f4dc75672ffb32453 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Tue, 30 Aug 2016 01:12:10 +0000 Subject: [PATCH] [sanitizer-coverage] add two more modes of instrumentation: trace-div and trace-gep, mostly usaful for value-profile-based fuzzing; llvm part llvm-svn: 280043 --- include/llvm/Transforms/Instrumentation.h | 5 +- .../Instrumentation/SanitizerCoverage.cpp | 81 +++++++++++++++++-- .../SanitizerCoverage/cmp-tracing.ll | 4 +- .../SanitizerCoverage/div-tracing.ll | 37 +++++++++ .../SanitizerCoverage/gep-tracing.ll | 32 ++++++++ .../SanitizerCoverage/switch-tracing.ll | 4 +- 6 files changed, 152 insertions(+), 11 deletions(-) create mode 100644 test/Instrumentation/SanitizerCoverage/div-tracing.ll create mode 100644 test/Instrumentation/SanitizerCoverage/gep-tracing.ll diff --git a/include/llvm/Transforms/Instrumentation.h b/include/llvm/Transforms/Instrumentation.h index 09eef7e0750..9517fdf669e 100644 --- a/include/llvm/Transforms/Instrumentation.h +++ b/include/llvm/Transforms/Instrumentation.h @@ -136,7 +136,8 @@ ModulePass *createEfficiencySanitizerPass( struct SanitizerCoverageOptions { SanitizerCoverageOptions() : CoverageType(SCK_None), IndirectCalls(false), TraceBB(false), - TraceCmp(false), Use8bitCounters(false), TracePC(false) {} + TraceCmp(false), TraceDiv(false), TraceGep(false), + Use8bitCounters(false), TracePC(false) {} enum Type { SCK_None = 0, @@ -147,6 +148,8 @@ struct SanitizerCoverageOptions { bool IndirectCalls; bool TraceBB; bool TraceCmp; + bool TraceDiv; + bool TraceGep; bool Use8bitCounters; bool TracePC; }; diff --git a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp index bf9ecccd46d..5a70598329a 100644 --- a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -71,6 +71,9 @@ static const char *const SanCovTraceCmp1 = "__sanitizer_cov_trace_cmp1"; static const char *const SanCovTraceCmp2 = "__sanitizer_cov_trace_cmp2"; static const char *const SanCovTraceCmp4 = "__sanitizer_cov_trace_cmp4"; static const char *const SanCovTraceCmp8 = "__sanitizer_cov_trace_cmp8"; +static const char *const SanCovTraceDiv4 = "__sanitizer_cov_trace_div4"; +static const char *const SanCovTraceDiv8 = "__sanitizer_cov_trace_div8"; +static const char *const SanCovTraceGep = "__sanitizer_cov_trace_gep"; static const char *const SanCovTraceSwitchName = "__sanitizer_cov_trace_switch"; static const char *const SanCovModuleCtorName = "sancov.module_ctor"; static const uint64_t SanCtorAndDtorPriority = 2; @@ -99,10 +102,17 @@ static cl::opt ClExperimentalTracePC("sanitizer-coverage-trace-pc", cl::Hidden, cl::init(false)); static cl::opt - ClExperimentalCMPTracing("sanitizer-coverage-experimental-trace-compares", - cl::desc("Experimental tracing of CMP and similar " - "instructions"), - cl::Hidden, cl::init(false)); + ClCMPTracing("sanitizer-coverage-trace-compares", + cl::desc("Tracing of CMP and similar instructions"), + cl::Hidden, cl::init(false)); + +static cl::opt ClDIVTracing("sanitizer-coverage-trace-divs", + cl::desc("Tracing of DIV instructions"), + cl::Hidden, cl::init(false)); + +static cl::opt ClGEPTracing("sanitizer-coverage-trace-geps", + cl::desc("Tracing of GEP instructions"), + cl::Hidden, cl::init(false)); static cl::opt ClPruneBlocks("sanitizer-coverage-prune-blocks", @@ -150,7 +160,9 @@ SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) { Options.CoverageType = std::max(Options.CoverageType, CLOpts.CoverageType); Options.IndirectCalls |= CLOpts.IndirectCalls; Options.TraceBB |= ClExperimentalTracing; - Options.TraceCmp |= ClExperimentalCMPTracing; + Options.TraceCmp |= ClCMPTracing; + Options.TraceDiv |= ClDIVTracing; + Options.TraceGep |= ClGEPTracing; Options.Use8bitCounters |= ClUse8bitCounters; Options.TracePC |= ClExperimentalTracePC; return Options; @@ -177,6 +189,10 @@ private: void InjectCoverageForIndirectCalls(Function &F, ArrayRef IndirCalls); void InjectTraceForCmp(Function &F, ArrayRef CmpTraceTargets); + void InjectTraceForDiv(Function &F, + ArrayRef DivTraceTargets); + void InjectTraceForGep(Function &F, + ArrayRef GepTraceTargets); void InjectTraceForSwitch(Function &F, ArrayRef SwitchTraceTargets); bool InjectCoverage(Function &F, ArrayRef AllBlocks); @@ -192,6 +208,8 @@ private: Function *SanCovIndirCallFunction, *SanCovTracePCIndir; Function *SanCovTraceEnter, *SanCovTraceBB, *SanCovTracePC; Function *SanCovTraceCmpFunction[4]; + Function *SanCovTraceDivFunction[2]; + Function *SanCovTraceGepFunction; Function *SanCovTraceSwitchFunction; InlineAsm *EmptyAsm; Type *IntptrTy, *Int64Ty, *Int64PtrTy; @@ -242,6 +260,16 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { SanCovTraceCmpFunction[3] = checkSanitizerInterfaceFunction(M.getOrInsertFunction( SanCovTraceCmp8, VoidTy, Int64Ty, Int64Ty, nullptr)); + + SanCovTraceDivFunction[0] = + checkSanitizerInterfaceFunction(M.getOrInsertFunction( + SanCovTraceDiv4, VoidTy, IRB.getInt32Ty(), nullptr)); + SanCovTraceDivFunction[1] = + checkSanitizerInterfaceFunction(M.getOrInsertFunction( + SanCovTraceDiv8, VoidTy, Int64Ty, nullptr)); + SanCovTraceGepFunction = + checkSanitizerInterfaceFunction(M.getOrInsertFunction( + SanCovTraceGep, VoidTy, IntptrTy, nullptr)); SanCovTraceSwitchFunction = checkSanitizerInterfaceFunction(M.getOrInsertFunction( SanCovTraceSwitchName, VoidTy, Int64Ty, Int64PtrTy, nullptr)); @@ -379,6 +407,8 @@ bool SanitizerCoverageModule::runOnFunction(Function &F) { SmallVector BlocksToInstrument; SmallVector CmpTraceTargets; SmallVector SwitchTraceTargets; + SmallVector DivTraceTargets; + SmallVector GepTraceTargets; const DominatorTree *DT = &getAnalysis(F).getDomTree(); @@ -400,13 +430,23 @@ bool SanitizerCoverageModule::runOnFunction(Function &F) { if (isa(&Inst)) SwitchTraceTargets.push_back(&Inst); } - } + if (Options.TraceDiv) + if (BinaryOperator *BO = dyn_cast(&Inst)) + if (BO->getOpcode() == Instruction::SDiv || + BO->getOpcode() == Instruction::UDiv) + DivTraceTargets.push_back(BO); + if (Options.TraceGep) + if (GetElementPtrInst *GEP = dyn_cast(&Inst)) + GepTraceTargets.push_back(GEP); + } } InjectCoverage(F, BlocksToInstrument); InjectCoverageForIndirectCalls(F, IndirCalls); InjectTraceForCmp(F, CmpTraceTargets); InjectTraceForSwitch(F, SwitchTraceTargets); + InjectTraceForDiv(F, DivTraceTargets); + InjectTraceForGep(F, GepTraceTargets); return true; } @@ -499,6 +539,35 @@ void SanitizerCoverageModule::InjectTraceForSwitch( } } +void SanitizerCoverageModule::InjectTraceForDiv( + Function &, ArrayRef DivTraceTargets) { + for (auto BO : DivTraceTargets) { + IRBuilder<> IRB(BO); + Value *A1 = BO->getOperand(1); + if (isa(A1)) continue; + if (!A1->getType()->isIntegerTy()) + continue; + uint64_t TypeSize = DL->getTypeStoreSizeInBits(A1->getType()); + int CallbackIdx = TypeSize == 32 ? 0 : + TypeSize == 64 ? 1 : -1; + if (CallbackIdx < 0) continue; + auto Ty = Type::getIntNTy(*C, TypeSize); + IRB.CreateCall(SanCovTraceDivFunction[CallbackIdx], + {IRB.CreateIntCast(A1, Ty, true)}); + } +} + +void SanitizerCoverageModule::InjectTraceForGep( + Function &, ArrayRef GepTraceTargets) { + for (auto GEP : GepTraceTargets) { + IRBuilder<> IRB(GEP); + for (auto I = GEP->idx_begin(); I != GEP->idx_end(); ++I) + if (!isa(*I)) + IRB.CreateCall(SanCovTraceGepFunction, + {IRB.CreateIntCast(*I, IntptrTy, true)}); + } +} + void SanitizerCoverageModule::InjectTraceForCmp( Function &, ArrayRef CmpTraceTargets) { for (auto I : CmpTraceTargets) { diff --git a/test/Instrumentation/SanitizerCoverage/cmp-tracing.ll b/test/Instrumentation/SanitizerCoverage/cmp-tracing.ll index 7bc79fa0ace..fda6f251bc8 100644 --- a/test/Instrumentation/SanitizerCoverage/cmp-tracing.ll +++ b/test/Instrumentation/SanitizerCoverage/cmp-tracing.ll @@ -1,5 +1,5 @@ -; Test -sanitizer-coverage-experimental-trace-compares=1 -; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -sanitizer-coverage-experimental-trace-compares=1 -S | FileCheck %s +; Test -sanitizer-coverage-trace-compares=1 +; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -sanitizer-coverage-trace-compares=1 -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" diff --git a/test/Instrumentation/SanitizerCoverage/div-tracing.ll b/test/Instrumentation/SanitizerCoverage/div-tracing.ll new file mode 100644 index 00000000000..aee872c130b --- /dev/null +++ b/test/Instrumentation/SanitizerCoverage/div-tracing.ll @@ -0,0 +1,37 @@ +; Test -sanitizer-coverage-trace-divs=1 +; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -sanitizer-coverage-trace-divs=1 -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" + +define i32 @div_a_b(i32 %a, i32 %b) local_unnamed_addr { +entry: + %div = sdiv i32 %a, %b + ret i32 %div +} + +; CHECK-LABEL: div_a_b +; CHECK: call void @__sanitizer_cov_trace_div4(i32 %b) +; CHECK: ret + + +define i32 @div_a_10(i32 %a) local_unnamed_addr { +entry: + %div = sdiv i32 %a, 10 + ret i32 %div +} + +; CHECK-LABEL: div_a_10 +; CHECK-NOT: __sanitizer_cov_trace_div +; CHECK: ret + +define i64 @div_a_b_64(i64 %a, i64 %b) local_unnamed_addr { +entry: + %div = udiv i64 %a, %b + ret i64 %div +} + +; CHECK-LABEL: div_a_b +; CHECK: call void @__sanitizer_cov_trace_div8(i64 %b) +; CHECK: ret + diff --git a/test/Instrumentation/SanitizerCoverage/gep-tracing.ll b/test/Instrumentation/SanitizerCoverage/gep-tracing.ll new file mode 100644 index 00000000000..ed6cf2d49a8 --- /dev/null +++ b/test/Instrumentation/SanitizerCoverage/gep-tracing.ll @@ -0,0 +1,32 @@ +; Test -sanitizer-coverage-trace-geps=1 +; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -sanitizer-coverage-trace-geps=1 -S | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @gep_1(i32* nocapture %a, i32 %i) { +entry: + %idxprom = sext i32 %i to i64 + %arrayidx = getelementptr inbounds i32, i32* %a, i64 %idxprom + store i32 0, i32* %arrayidx, align 4 + ret void +} + +; CHECK-LABEL: define void @gep_1(i32* nocapture %a, i32 %i) +; CHECK: call void @__sanitizer_cov_trace_gep(i64 %idxprom) +; CHECK: ret void + + +define void @gep_2([1000 x i32]* nocapture %a, i32 %i, i32 %j) { +entry: + %idxprom = sext i32 %j to i64 + %idxprom1 = sext i32 %i to i64 + %arrayidx2 = getelementptr inbounds [1000 x i32], [1000 x i32]* %a, i64 %idxprom1, i64 %idxprom + store i32 0, i32* %arrayidx2, align 4 + ret void +} + +; CHECK-LABEL: define void @gep_2([1000 x i32]* nocapture %a, i32 %i, i32 %j) { +; CHECK: call void @__sanitizer_cov_trace_gep(i64 %idxprom1) +; CHECK: call void @__sanitizer_cov_trace_gep(i64 %idxprom) +; CHECK: ret void diff --git a/test/Instrumentation/SanitizerCoverage/switch-tracing.ll b/test/Instrumentation/SanitizerCoverage/switch-tracing.ll index cf1fcf10208..76a5a3dec0b 100644 --- a/test/Instrumentation/SanitizerCoverage/switch-tracing.ll +++ b/test/Instrumentation/SanitizerCoverage/switch-tracing.ll @@ -1,5 +1,5 @@ -; Test -sanitizer-coverage-experimental-trace-compares=1 (instrumenting a switch) -; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -sanitizer-coverage-experimental-trace-compares=1 -S | FileCheck %s +; Test -sanitizer-coverage-trace-compares=1 (instrumenting a switch) +; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -sanitizer-coverage-trace-compares=1 -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"