mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-04 19:26:30 +00:00
[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
This commit is contained in:
parent
62419dd0e2
commit
a0e2bc22aa
@ -136,7 +136,8 @@ ModulePass *createEfficiencySanitizerPass(
|
|||||||
struct SanitizerCoverageOptions {
|
struct SanitizerCoverageOptions {
|
||||||
SanitizerCoverageOptions()
|
SanitizerCoverageOptions()
|
||||||
: CoverageType(SCK_None), IndirectCalls(false), TraceBB(false),
|
: 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 {
|
enum Type {
|
||||||
SCK_None = 0,
|
SCK_None = 0,
|
||||||
@ -147,6 +148,8 @@ struct SanitizerCoverageOptions {
|
|||||||
bool IndirectCalls;
|
bool IndirectCalls;
|
||||||
bool TraceBB;
|
bool TraceBB;
|
||||||
bool TraceCmp;
|
bool TraceCmp;
|
||||||
|
bool TraceDiv;
|
||||||
|
bool TraceGep;
|
||||||
bool Use8bitCounters;
|
bool Use8bitCounters;
|
||||||
bool TracePC;
|
bool TracePC;
|
||||||
};
|
};
|
||||||
|
@ -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 SanCovTraceCmp2 = "__sanitizer_cov_trace_cmp2";
|
||||||
static const char *const SanCovTraceCmp4 = "__sanitizer_cov_trace_cmp4";
|
static const char *const SanCovTraceCmp4 = "__sanitizer_cov_trace_cmp4";
|
||||||
static const char *const SanCovTraceCmp8 = "__sanitizer_cov_trace_cmp8";
|
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 SanCovTraceSwitchName = "__sanitizer_cov_trace_switch";
|
||||||
static const char *const SanCovModuleCtorName = "sancov.module_ctor";
|
static const char *const SanCovModuleCtorName = "sancov.module_ctor";
|
||||||
static const uint64_t SanCtorAndDtorPriority = 2;
|
static const uint64_t SanCtorAndDtorPriority = 2;
|
||||||
@ -99,10 +102,17 @@ static cl::opt<bool> ClExperimentalTracePC("sanitizer-coverage-trace-pc",
|
|||||||
cl::Hidden, cl::init(false));
|
cl::Hidden, cl::init(false));
|
||||||
|
|
||||||
static cl::opt<bool>
|
static cl::opt<bool>
|
||||||
ClExperimentalCMPTracing("sanitizer-coverage-experimental-trace-compares",
|
ClCMPTracing("sanitizer-coverage-trace-compares",
|
||||||
cl::desc("Experimental tracing of CMP and similar "
|
cl::desc("Tracing of CMP and similar instructions"),
|
||||||
"instructions"),
|
cl::Hidden, cl::init(false));
|
||||||
cl::Hidden, cl::init(false));
|
|
||||||
|
static cl::opt<bool> ClDIVTracing("sanitizer-coverage-trace-divs",
|
||||||
|
cl::desc("Tracing of DIV instructions"),
|
||||||
|
cl::Hidden, cl::init(false));
|
||||||
|
|
||||||
|
static cl::opt<bool> ClGEPTracing("sanitizer-coverage-trace-geps",
|
||||||
|
cl::desc("Tracing of GEP instructions"),
|
||||||
|
cl::Hidden, cl::init(false));
|
||||||
|
|
||||||
static cl::opt<bool>
|
static cl::opt<bool>
|
||||||
ClPruneBlocks("sanitizer-coverage-prune-blocks",
|
ClPruneBlocks("sanitizer-coverage-prune-blocks",
|
||||||
@ -150,7 +160,9 @@ SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
|
|||||||
Options.CoverageType = std::max(Options.CoverageType, CLOpts.CoverageType);
|
Options.CoverageType = std::max(Options.CoverageType, CLOpts.CoverageType);
|
||||||
Options.IndirectCalls |= CLOpts.IndirectCalls;
|
Options.IndirectCalls |= CLOpts.IndirectCalls;
|
||||||
Options.TraceBB |= ClExperimentalTracing;
|
Options.TraceBB |= ClExperimentalTracing;
|
||||||
Options.TraceCmp |= ClExperimentalCMPTracing;
|
Options.TraceCmp |= ClCMPTracing;
|
||||||
|
Options.TraceDiv |= ClDIVTracing;
|
||||||
|
Options.TraceGep |= ClGEPTracing;
|
||||||
Options.Use8bitCounters |= ClUse8bitCounters;
|
Options.Use8bitCounters |= ClUse8bitCounters;
|
||||||
Options.TracePC |= ClExperimentalTracePC;
|
Options.TracePC |= ClExperimentalTracePC;
|
||||||
return Options;
|
return Options;
|
||||||
@ -177,6 +189,10 @@ private:
|
|||||||
void InjectCoverageForIndirectCalls(Function &F,
|
void InjectCoverageForIndirectCalls(Function &F,
|
||||||
ArrayRef<Instruction *> IndirCalls);
|
ArrayRef<Instruction *> IndirCalls);
|
||||||
void InjectTraceForCmp(Function &F, ArrayRef<Instruction *> CmpTraceTargets);
|
void InjectTraceForCmp(Function &F, ArrayRef<Instruction *> CmpTraceTargets);
|
||||||
|
void InjectTraceForDiv(Function &F,
|
||||||
|
ArrayRef<BinaryOperator *> DivTraceTargets);
|
||||||
|
void InjectTraceForGep(Function &F,
|
||||||
|
ArrayRef<GetElementPtrInst *> GepTraceTargets);
|
||||||
void InjectTraceForSwitch(Function &F,
|
void InjectTraceForSwitch(Function &F,
|
||||||
ArrayRef<Instruction *> SwitchTraceTargets);
|
ArrayRef<Instruction *> SwitchTraceTargets);
|
||||||
bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks);
|
bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks);
|
||||||
@ -192,6 +208,8 @@ private:
|
|||||||
Function *SanCovIndirCallFunction, *SanCovTracePCIndir;
|
Function *SanCovIndirCallFunction, *SanCovTracePCIndir;
|
||||||
Function *SanCovTraceEnter, *SanCovTraceBB, *SanCovTracePC;
|
Function *SanCovTraceEnter, *SanCovTraceBB, *SanCovTracePC;
|
||||||
Function *SanCovTraceCmpFunction[4];
|
Function *SanCovTraceCmpFunction[4];
|
||||||
|
Function *SanCovTraceDivFunction[2];
|
||||||
|
Function *SanCovTraceGepFunction;
|
||||||
Function *SanCovTraceSwitchFunction;
|
Function *SanCovTraceSwitchFunction;
|
||||||
InlineAsm *EmptyAsm;
|
InlineAsm *EmptyAsm;
|
||||||
Type *IntptrTy, *Int64Ty, *Int64PtrTy;
|
Type *IntptrTy, *Int64Ty, *Int64PtrTy;
|
||||||
@ -242,6 +260,16 @@ bool SanitizerCoverageModule::runOnModule(Module &M) {
|
|||||||
SanCovTraceCmpFunction[3] =
|
SanCovTraceCmpFunction[3] =
|
||||||
checkSanitizerInterfaceFunction(M.getOrInsertFunction(
|
checkSanitizerInterfaceFunction(M.getOrInsertFunction(
|
||||||
SanCovTraceCmp8, VoidTy, Int64Ty, Int64Ty, nullptr));
|
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 =
|
SanCovTraceSwitchFunction =
|
||||||
checkSanitizerInterfaceFunction(M.getOrInsertFunction(
|
checkSanitizerInterfaceFunction(M.getOrInsertFunction(
|
||||||
SanCovTraceSwitchName, VoidTy, Int64Ty, Int64PtrTy, nullptr));
|
SanCovTraceSwitchName, VoidTy, Int64Ty, Int64PtrTy, nullptr));
|
||||||
@ -379,6 +407,8 @@ bool SanitizerCoverageModule::runOnFunction(Function &F) {
|
|||||||
SmallVector<BasicBlock *, 16> BlocksToInstrument;
|
SmallVector<BasicBlock *, 16> BlocksToInstrument;
|
||||||
SmallVector<Instruction *, 8> CmpTraceTargets;
|
SmallVector<Instruction *, 8> CmpTraceTargets;
|
||||||
SmallVector<Instruction *, 8> SwitchTraceTargets;
|
SmallVector<Instruction *, 8> SwitchTraceTargets;
|
||||||
|
SmallVector<BinaryOperator *, 8> DivTraceTargets;
|
||||||
|
SmallVector<GetElementPtrInst *, 8> GepTraceTargets;
|
||||||
|
|
||||||
const DominatorTree *DT =
|
const DominatorTree *DT =
|
||||||
&getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
|
&getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
|
||||||
@ -400,13 +430,23 @@ bool SanitizerCoverageModule::runOnFunction(Function &F) {
|
|||||||
if (isa<SwitchInst>(&Inst))
|
if (isa<SwitchInst>(&Inst))
|
||||||
SwitchTraceTargets.push_back(&Inst);
|
SwitchTraceTargets.push_back(&Inst);
|
||||||
}
|
}
|
||||||
}
|
if (Options.TraceDiv)
|
||||||
|
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(&Inst))
|
||||||
|
if (BO->getOpcode() == Instruction::SDiv ||
|
||||||
|
BO->getOpcode() == Instruction::UDiv)
|
||||||
|
DivTraceTargets.push_back(BO);
|
||||||
|
if (Options.TraceGep)
|
||||||
|
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(&Inst))
|
||||||
|
GepTraceTargets.push_back(GEP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InjectCoverage(F, BlocksToInstrument);
|
InjectCoverage(F, BlocksToInstrument);
|
||||||
InjectCoverageForIndirectCalls(F, IndirCalls);
|
InjectCoverageForIndirectCalls(F, IndirCalls);
|
||||||
InjectTraceForCmp(F, CmpTraceTargets);
|
InjectTraceForCmp(F, CmpTraceTargets);
|
||||||
InjectTraceForSwitch(F, SwitchTraceTargets);
|
InjectTraceForSwitch(F, SwitchTraceTargets);
|
||||||
|
InjectTraceForDiv(F, DivTraceTargets);
|
||||||
|
InjectTraceForGep(F, GepTraceTargets);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -499,6 +539,35 @@ void SanitizerCoverageModule::InjectTraceForSwitch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SanitizerCoverageModule::InjectTraceForDiv(
|
||||||
|
Function &, ArrayRef<BinaryOperator *> DivTraceTargets) {
|
||||||
|
for (auto BO : DivTraceTargets) {
|
||||||
|
IRBuilder<> IRB(BO);
|
||||||
|
Value *A1 = BO->getOperand(1);
|
||||||
|
if (isa<ConstantInt>(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<GetElementPtrInst *> GepTraceTargets) {
|
||||||
|
for (auto GEP : GepTraceTargets) {
|
||||||
|
IRBuilder<> IRB(GEP);
|
||||||
|
for (auto I = GEP->idx_begin(); I != GEP->idx_end(); ++I)
|
||||||
|
if (!isa<ConstantInt>(*I))
|
||||||
|
IRB.CreateCall(SanCovTraceGepFunction,
|
||||||
|
{IRB.CreateIntCast(*I, IntptrTy, true)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SanitizerCoverageModule::InjectTraceForCmp(
|
void SanitizerCoverageModule::InjectTraceForCmp(
|
||||||
Function &, ArrayRef<Instruction *> CmpTraceTargets) {
|
Function &, ArrayRef<Instruction *> CmpTraceTargets) {
|
||||||
for (auto I : CmpTraceTargets) {
|
for (auto I : CmpTraceTargets) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
; Test -sanitizer-coverage-experimental-trace-compares=1
|
; Test -sanitizer-coverage-trace-compares=1
|
||||||
; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -sanitizer-coverage-experimental-trace-compares=1 -S | FileCheck %s
|
; 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 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"
|
target triple = "x86_64-unknown-linux-gnu"
|
||||||
|
37
test/Instrumentation/SanitizerCoverage/div-tracing.ll
Normal file
37
test/Instrumentation/SanitizerCoverage/div-tracing.ll
Normal file
@ -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
|
||||||
|
|
32
test/Instrumentation/SanitizerCoverage/gep-tracing.ll
Normal file
32
test/Instrumentation/SanitizerCoverage/gep-tracing.ll
Normal file
@ -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
|
@ -1,5 +1,5 @@
|
|||||||
; Test -sanitizer-coverage-experimental-trace-compares=1 (instrumenting a switch)
|
; Test -sanitizer-coverage-trace-compares=1 (instrumenting a switch)
|
||||||
; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -sanitizer-coverage-experimental-trace-compares=1 -S | FileCheck %s
|
; 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 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"
|
target triple = "x86_64-unknown-linux-gnu"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user