llvm.org GIT mirror llvm / a77d9f7
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 Peter Collingbourne 7 years ago
2 changed file(s) with 71 addition(s) and 2 deletion(s). Raw diff Collapse all Expand all
9494 cl::desc("Use the argument ABI rather than the TLS ABI"),
9595 cl::Hidden);
9696
97 static cl::opt ClDebugNonzeroLabels(
98 "dfsan-debug-nonzero-labels",
99 cl::desc("Insert calls to __dfsan_nonzero_label on observing a parameter, "
100 "load or return with a nonzero label"),
101 cl::Hidden);
102
97103 namespace {
98104
99105 class DataFlowSanitizer : public ModulePass {
159165 FunctionType *DFSanUnionLoadFnTy;
160166 FunctionType *DFSanUnimplementedFnTy;
161167 FunctionType *DFSanSetLabelFnTy;
168 FunctionType *DFSanNonzeroLabelFnTy;
162169 Constant *DFSanUnionFn;
163170 Constant *DFSanUnionLoadFn;
164171 Constant *DFSanUnimplementedFn;
165172 Constant *DFSanSetLabelFn;
173 Constant *DFSanNonzeroLabelFn;
166174 MDNode *ColdCallWeights;
167175 OwningPtr ABIList;
168176 DenseMap UnwrappedFnMap;
196204 DenseMap AllocaShadowMap;
197205 std::vector > PHIFixups;
198206 DenseSet SkipInsts;
207 DenseSet NonZeroChecks;
199208
200209 DFSanFunction(DataFlowSanitizer &DFS, Function *F, bool IsNativeABI)
201210 : DFS(DFS), F(F), IA(DFS.getInstrumentedABI()),
310319 Type *DFSanSetLabelArgs[3] = { ShadowTy, Type::getInt8PtrTy(*Ctx), IntptrTy };
311320 DFSanSetLabelFnTy = FunctionType::get(Type::getVoidTy(*Ctx),
312321 DFSanSetLabelArgs, /*isVarArg=*/false);
322 DFSanNonzeroLabelFnTy = FunctionType::get(
323 Type::getVoidTy(*Ctx), ArrayRef(), /*isVarArg=*/false);
313324
314325 if (GetArgTLSPtr) {
315326 Type *ArgTLSTy = ArrayType::get(ShadowTy, 64);
388399 if (Function *F = dyn_cast(DFSanSetLabelFn)) {
389400 F->addAttribute(1, Attribute::ZExt);
390401 }
402 DFSanNonzeroLabelFn =
403 Mod->getOrInsertFunction("__dfsan_nonzero_label", DFSanNonzeroLabelFnTy);
391404
392405 std::vector FnsToInstrument;
393406 llvm::SmallPtrSet FnsWithNativeABI;
396409 i != DFSanUnionFn &&
397410 i != DFSanUnionLoadFn &&
398411 i != DFSanUnimplementedFn &&
399 i != DFSanSetLabelFn)
412 i != DFSanSetLabelFn &&
413 i != DFSanNonzeroLabelFn)
400414 FnsToInstrument.push_back(&*i);
401415 }
402416
559573 val, DFSF.getShadow(i->first->getIncomingValue(val)));
560574 }
561575 }
576
577 // -dfsan-debug-nonzero-labels will split the CFG in all kinds of crazy
578 // places (i.e. instructions in basic blocks we haven't even begun visiting
579 // yet). To make our life easier, do this work in a pass after the main
580 // instrumentation.
581 if (ClDebugNonzeroLabels) {
582 for (DenseSet::iterator i = DFSF.NonZeroChecks.begin(),
583 e = DFSF.NonZeroChecks.end();
584 i != e; ++i) {
585 Instruction *Pos;
586 if (Instruction *I = dyn_cast(*i))
587 Pos = I->getNextNode();
588 else
589 Pos = DFSF.F->getEntryBlock().begin();
590 while (isa(Pos) || isa(Pos))
591 Pos = Pos->getNextNode();
592 IRBuilder<> IRB(Pos);
593 Instruction *NeInst = cast(
594 IRB.CreateICmpNE(*i, DFSF.DFS.ZeroShadow));
595 BranchInst *BI = cast(SplitBlockAndInsertIfThen(
596 NeInst, /*Unreachable=*/ false, ColdCallWeights));
597 IRBuilder<> ThenIRB(BI);
598 ThenIRB.CreateCall(DFSF.DFS.DFSanNonzeroLabelFn);
599 }
600 }
562601 }
563602
564603 return false;
617656 break;
618657 }
619658 }
659 NonZeroChecks.insert(Shadow);
620660 } else {
621661 Shadow = DFS.ZeroShadow;
622662 }
813853 Value *LoadedShadow =
814854 DFSF.loadShadow(LI.getPointerOperand(), Size, Align, &LI);
815855 Value *PtrShadow = DFSF.getShadow(LI.getPointerOperand());
816 DFSF.setShadow(&LI, DFSF.DFS.combineShadows(LoadedShadow, PtrShadow, &LI));
856 Value *CombinedShadow = DFSF.DFS.combineShadows(LoadedShadow, PtrShadow, &LI);
857 if (CombinedShadow != DFSF.DFS.ZeroShadow)
858 DFSF.NonZeroChecks.insert(CombinedShadow);
859
860 DFSF.setShadow(&LI, CombinedShadow);
817861 }
818862
819863 void DFSanFunction::storeShadow(Value *Addr, uint64_t Size, uint64_t Align,
11301174 LoadInst *LI = NextIRB.CreateLoad(DFSF.getRetvalTLS());
11311175 DFSF.SkipInsts.insert(LI);
11321176 DFSF.setShadow(CS.getInstruction(), LI);
1177 DFSF.NonZeroChecks.insert(LI);
11331178 }
11341179 }
11351180
11831228 ExtractValueInst::Create(NewCS.getInstruction(), 1, "", Next);
11841229 DFSF.SkipInsts.insert(ExShadow);
11851230 DFSF.setShadow(ExVal, ExShadow);
1231 DFSF.NonZeroChecks.insert(ExShadow);
11861232
11871233 CS.getInstruction()->replaceAllUsesWith(ExVal);
11881234 }
0 ; RUN: opt < %s -dfsan -dfsan-args-abi -dfsan-debug-nonzero-labels -S | FileCheck %s
1 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"
2
3 declare i32 @g()
4
5 ; CHECK: define { i32, i16 } @f(i32, i16)
6 define i32 @f(i32) {
7 ; CHECK: [[LOCALLABELALLOCA:%.*]] = alloca i16
8 ; CHECK: [[ARGCMP:%.*]] = icmp ne i16 %1, 0
9 ; CHECK: br i1 [[ARGCMP]]
10 %i = alloca i32
11 store i32 %0, i32* %i
12 ; CHECK: [[CALL:%.*]] = call { i32, i16 } @g()
13 ; CHECK: [[CALLLABEL:%.*]] = extractvalue { i32, i16 } [[CALL]], 1
14 ; CHECK: [[CALLCMP:%.*]] = icmp ne i16 [[CALLLABEL]], 0
15 ; CHECK: br i1 [[CALLCMP]]
16 %call = call i32 @g()
17 ; CHECK: [[LOCALLABEL:%.*]] = load i16* [[LOCALLABELALLOCA]]
18 ; CHECK: [[LOCALCMP:%.*]] = icmp ne i16 [[LOCALLABEL]], 0
19 ; CHECK: br i1 [[LOCALCMP]]
20 %load = load i32* %i
21 ret i32 %load
22 }