mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-24 21:14:56 +00:00
DataFlowSanitizer: Add a debugging feature to help us track nonzero labels.
Summary: When the -dfsan-debug-nonzero-labels parameter is supplied, the code is instrumented such that when a call parameter, return value or load produces a nonzero label, the function __dfsan_nonzero_label is called. The idea is that a debugger breakpoint can be set on this function in a nominally label-free program to help identify any bugs in the instrumentation pass causing labels to be introduced. Reviewers: eugenis CC: llvm-commits Differential Revision: http://llvm-reviews.chandlerc.com/D1405 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188472 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e427297997
commit
a77d9f726a
@ -95,6 +95,12 @@ static cl::opt<bool> ClArgsABI(
|
||||
cl::desc("Use the argument ABI rather than the TLS ABI"),
|
||||
cl::Hidden);
|
||||
|
||||
static cl::opt<bool> ClDebugNonzeroLabels(
|
||||
"dfsan-debug-nonzero-labels",
|
||||
cl::desc("Insert calls to __dfsan_nonzero_label on observing a parameter, "
|
||||
"load or return with a nonzero label"),
|
||||
cl::Hidden);
|
||||
|
||||
namespace {
|
||||
|
||||
class DataFlowSanitizer : public ModulePass {
|
||||
@ -160,10 +166,12 @@ class DataFlowSanitizer : public ModulePass {
|
||||
FunctionType *DFSanUnionLoadFnTy;
|
||||
FunctionType *DFSanUnimplementedFnTy;
|
||||
FunctionType *DFSanSetLabelFnTy;
|
||||
FunctionType *DFSanNonzeroLabelFnTy;
|
||||
Constant *DFSanUnionFn;
|
||||
Constant *DFSanUnionLoadFn;
|
||||
Constant *DFSanUnimplementedFn;
|
||||
Constant *DFSanSetLabelFn;
|
||||
Constant *DFSanNonzeroLabelFn;
|
||||
MDNode *ColdCallWeights;
|
||||
OwningPtr<SpecialCaseList> ABIList;
|
||||
DenseMap<Value *, Function *> UnwrappedFnMap;
|
||||
@ -197,6 +205,7 @@ struct DFSanFunction {
|
||||
DenseMap<AllocaInst *, AllocaInst *> AllocaShadowMap;
|
||||
std::vector<std::pair<PHINode *, PHINode *> > PHIFixups;
|
||||
DenseSet<Instruction *> SkipInsts;
|
||||
DenseSet<Value *> NonZeroChecks;
|
||||
|
||||
DFSanFunction(DataFlowSanitizer &DFS, Function *F, bool IsNativeABI)
|
||||
: DFS(DFS), F(F), IA(DFS.getInstrumentedABI()),
|
||||
@ -311,6 +320,8 @@ bool DataFlowSanitizer::doInitialization(Module &M) {
|
||||
Type *DFSanSetLabelArgs[3] = { ShadowTy, Type::getInt8PtrTy(*Ctx), IntptrTy };
|
||||
DFSanSetLabelFnTy = FunctionType::get(Type::getVoidTy(*Ctx),
|
||||
DFSanSetLabelArgs, /*isVarArg=*/false);
|
||||
DFSanNonzeroLabelFnTy = FunctionType::get(
|
||||
Type::getVoidTy(*Ctx), ArrayRef<Type *>(), /*isVarArg=*/false);
|
||||
|
||||
if (GetArgTLSPtr) {
|
||||
Type *ArgTLSTy = ArrayType::get(ShadowTy, 64);
|
||||
@ -389,6 +400,8 @@ bool DataFlowSanitizer::runOnModule(Module &M) {
|
||||
if (Function *F = dyn_cast<Function>(DFSanSetLabelFn)) {
|
||||
F->addAttribute(1, Attribute::ZExt);
|
||||
}
|
||||
DFSanNonzeroLabelFn =
|
||||
Mod->getOrInsertFunction("__dfsan_nonzero_label", DFSanNonzeroLabelFnTy);
|
||||
|
||||
std::vector<Function *> FnsToInstrument;
|
||||
llvm::SmallPtrSet<Function *, 2> FnsWithNativeABI;
|
||||
@ -397,7 +410,8 @@ bool DataFlowSanitizer::runOnModule(Module &M) {
|
||||
i != DFSanUnionFn &&
|
||||
i != DFSanUnionLoadFn &&
|
||||
i != DFSanUnimplementedFn &&
|
||||
i != DFSanSetLabelFn)
|
||||
i != DFSanSetLabelFn &&
|
||||
i != DFSanNonzeroLabelFn)
|
||||
FnsToInstrument.push_back(&*i);
|
||||
}
|
||||
|
||||
@ -560,6 +574,31 @@ bool DataFlowSanitizer::runOnModule(Module &M) {
|
||||
val, DFSF.getShadow(i->first->getIncomingValue(val)));
|
||||
}
|
||||
}
|
||||
|
||||
// -dfsan-debug-nonzero-labels will split the CFG in all kinds of crazy
|
||||
// places (i.e. instructions in basic blocks we haven't even begun visiting
|
||||
// yet). To make our life easier, do this work in a pass after the main
|
||||
// instrumentation.
|
||||
if (ClDebugNonzeroLabels) {
|
||||
for (DenseSet<Value *>::iterator i = DFSF.NonZeroChecks.begin(),
|
||||
e = DFSF.NonZeroChecks.end();
|
||||
i != e; ++i) {
|
||||
Instruction *Pos;
|
||||
if (Instruction *I = dyn_cast<Instruction>(*i))
|
||||
Pos = I->getNextNode();
|
||||
else
|
||||
Pos = DFSF.F->getEntryBlock().begin();
|
||||
while (isa<PHINode>(Pos) || isa<AllocaInst>(Pos))
|
||||
Pos = Pos->getNextNode();
|
||||
IRBuilder<> IRB(Pos);
|
||||
Instruction *NeInst = cast<Instruction>(
|
||||
IRB.CreateICmpNE(*i, DFSF.DFS.ZeroShadow));
|
||||
BranchInst *BI = cast<BranchInst>(SplitBlockAndInsertIfThen(
|
||||
NeInst, /*Unreachable=*/ false, ColdCallWeights));
|
||||
IRBuilder<> ThenIRB(BI);
|
||||
ThenIRB.CreateCall(DFSF.DFS.DFSanNonzeroLabelFn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -618,6 +657,7 @@ Value *DFSanFunction::getShadow(Value *V) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
NonZeroChecks.insert(Shadow);
|
||||
} else {
|
||||
Shadow = DFS.ZeroShadow;
|
||||
}
|
||||
@ -814,7 +854,11 @@ void DFSanVisitor::visitLoadInst(LoadInst &LI) {
|
||||
Value *LoadedShadow =
|
||||
DFSF.loadShadow(LI.getPointerOperand(), Size, Align, &LI);
|
||||
Value *PtrShadow = DFSF.getShadow(LI.getPointerOperand());
|
||||
DFSF.setShadow(&LI, DFSF.DFS.combineShadows(LoadedShadow, PtrShadow, &LI));
|
||||
Value *CombinedShadow = DFSF.DFS.combineShadows(LoadedShadow, PtrShadow, &LI);
|
||||
if (CombinedShadow != DFSF.DFS.ZeroShadow)
|
||||
DFSF.NonZeroChecks.insert(CombinedShadow);
|
||||
|
||||
DFSF.setShadow(&LI, CombinedShadow);
|
||||
}
|
||||
|
||||
void DFSanFunction::storeShadow(Value *Addr, uint64_t Size, uint64_t Align,
|
||||
@ -1131,6 +1175,7 @@ void DFSanVisitor::visitCallSite(CallSite CS) {
|
||||
LoadInst *LI = NextIRB.CreateLoad(DFSF.getRetvalTLS());
|
||||
DFSF.SkipInsts.insert(LI);
|
||||
DFSF.setShadow(CS.getInstruction(), LI);
|
||||
DFSF.NonZeroChecks.insert(LI);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1184,6 +1229,7 @@ void DFSanVisitor::visitCallSite(CallSite CS) {
|
||||
ExtractValueInst::Create(NewCS.getInstruction(), 1, "", Next);
|
||||
DFSF.SkipInsts.insert(ExShadow);
|
||||
DFSF.setShadow(ExVal, ExShadow);
|
||||
DFSF.NonZeroChecks.insert(ExShadow);
|
||||
|
||||
CS.getInstruction()->replaceAllUsesWith(ExVal);
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
; RUN: opt < %s -dfsan -dfsan-args-abi -dfsan-debug-nonzero-labels -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-S128"
|
||||
|
||||
declare i32 @g()
|
||||
|
||||
; CHECK: define { i32, i16 } @f(i32, i16)
|
||||
define i32 @f(i32) {
|
||||
; CHECK: [[LOCALLABELALLOCA:%.*]] = alloca i16
|
||||
; CHECK: [[ARGCMP:%.*]] = icmp ne i16 %1, 0
|
||||
; CHECK: br i1 [[ARGCMP]]
|
||||
%i = alloca i32
|
||||
store i32 %0, i32* %i
|
||||
; CHECK: [[CALL:%.*]] = call { i32, i16 } @g()
|
||||
; CHECK: [[CALLLABEL:%.*]] = extractvalue { i32, i16 } [[CALL]], 1
|
||||
; CHECK: [[CALLCMP:%.*]] = icmp ne i16 [[CALLLABEL]], 0
|
||||
; CHECK: br i1 [[CALLCMP]]
|
||||
%call = call i32 @g()
|
||||
; CHECK: [[LOCALLABEL:%.*]] = load i16* [[LOCALLABELALLOCA]]
|
||||
; CHECK: [[LOCALCMP:%.*]] = icmp ne i16 [[LOCALLABEL]], 0
|
||||
; CHECK: br i1 [[LOCALCMP]]
|
||||
%load = load i32* %i
|
||||
ret i32 %load
|
||||
}
|
Loading…
Reference in New Issue
Block a user