llvm.org GIT mirror llvm / c7ed63a
[esan|cfrag] Instrument GEP instr for struct field access. Summary: Instrument GEP instruction for counting the number of struct field address calculation to approximate the number of struct field accesses. Adds test struct_field_count_basic.ll to test the struct field instrumentation. Reviewers: bruening, aizatsky Subscribers: junbuml, zhaoqin, llvm-commits, eugenis, vitalybuka, kcc, bruening Differential Revision: http://reviews.llvm.org/D20892 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@271619 91177308-0d34-0410-b5e6-96231b3b80d8 Qin Zhao 4 years ago
2 changed file(s) with 156 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
6262 STATISTIC(NumAccessesWithIrregularSize,
6363 "Number of accesses with a size outside our targeted callout sizes");
6464 STATISTIC(NumIgnoredStructs, "Number of ignored structs");
65 STATISTIC(NumIgnoredGEPs, "Number of ignored GEP instructions");
66 STATISTIC(NumInstrumentedGEPs, "Number of instrumented GEP instructions");
6567
6668 static const uint64_t EsanCtorAndDtorPriority = 0;
6769 static const char *const EsanModuleCtorName = "esan.module_ctor";
144146 bool runOnFunction(Function &F, Module &M);
145147 bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL);
146148 bool instrumentMemIntrinsic(MemIntrinsic *MI);
149 bool instrumentGetElementPtr(Instruction *I, Module &M);
147150 bool shouldIgnoreMemoryAccess(Instruction *I);
148151 int getMemoryAccessFuncIndex(Value *Addr, const DataLayout &DL);
149152 Value *appToShadow(Value *Shadow, IRBuilder<> &IRB);
170173 Function *MemmoveFn, *MemcpyFn, *MemsetFn;
171174 Function *EsanCtorFunction;
172175 Function *EsanDtorFunction;
176 // Remember the counter variable for each struct type to avoid
177 // recomputing the variable name later during instrumentation.
178 std::map StructTyMap;
173179 };
174180 } // namespace
175181
320326 ConstantAggregateZero::get(CounterArrayTy),
321327 CounterNameStr);
322328
329 // Remember the counter variable for each struct type.
330 StructTyMap.insert(std::pair(StructTy, Counters));
331
323332 // FieldTypeNames.
324333 // We pass the field type name array to the runtime for better reporting.
325334 auto *TypeNameArrayTy = ArrayType::get(Int8PtrTy, StructTy->getNumElements());
476485 return false;
477486 SmallVector LoadsAndStores;
478487 SmallVector MemIntrinCalls;
488 SmallVector GetElementPtrs;
479489 bool Res = false;
480490 const DataLayout &DL = M.getDataLayout();
481491
487497 LoadsAndStores.push_back(&Inst);
488498 else if (isa(Inst))
489499 MemIntrinCalls.push_back(&Inst);
500 else if (isa(Inst))
501 GetElementPtrs.push_back(&Inst);
490502 }
491503 }
492504
499511 if (ClInstrumentMemIntrinsics) {
500512 for (auto Inst : MemIntrinCalls) {
501513 Res |= instrumentMemIntrinsic(cast(Inst));
514 }
515 }
516
517 if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag) {
518 for (auto Inst : GetElementPtrs) {
519 Res |= instrumentGetElementPtr(Inst, M);
502520 }
503521 }
504522
590608 return Res;
591609 }
592610
611 bool EfficiencySanitizer::instrumentGetElementPtr(Instruction *I, Module &M) {
612 GetElementPtrInst *GepInst = dyn_cast(I);
613 if (GepInst == nullptr || !isa(GepInst->getSourceElementType()) ||
614 StructTyMap.count(GepInst->getSourceElementType()) == 0 ||
615 !GepInst->hasAllConstantIndices() ||
616 // Only handle simple struct field GEP.
617 GepInst->getNumIndices() != 2) {
618 ++NumIgnoredGEPs;
619 return false;
620 }
621 StructType *StructTy = dyn_cast(GepInst->getSourceElementType());
622 if (shouldIgnoreStructType(StructTy)) {
623 ++NumIgnoredGEPs;
624 return false;
625 }
626 ++NumInstrumentedGEPs;
627 // Use the last index as the index within the struct.
628 ConstantInt *Idx = dyn_cast(GepInst->getOperand(2));
629 if (Idx == nullptr || Idx->getZExtValue() > StructTy->getNumElements())
630 return false;
631
632 GlobalVariable *CounterArray = StructTyMap[StructTy];
633 if (CounterArray == nullptr)
634 return false;
635 IRBuilder<> IRB(I);
636 Constant *Indices[2];
637 // Xref http://llvm.org/docs/LangRef.html#i-getelementptr and
638 // http://llvm.org/docs/GetElementPtr.html.
639 // The first index of the GEP instruction steps through the first operand,
640 // i.e., the array itself.
641 Indices[0] = ConstantInt::get(IRB.getInt32Ty(), 0);
642 // The second index is the index within the array.
643 Indices[1] = ConstantInt::get(IRB.getInt32Ty(), Idx->getZExtValue());
644 Constant *Counter =
645 ConstantExpr::getGetElementPtr(ArrayType::get(IRB.getInt64Ty(),
646 StructTy->getNumElements()),
647 CounterArray, Indices);
648 Value *Load = IRB.CreateLoad(Counter);
649 IRB.CreateStore(IRB.CreateAdd(Load, ConstantInt::get(IRB.getInt64Ty(), 1)),
650 Counter);
651 return true;
652 }
653
593654 int EfficiencySanitizer::getMemoryAccessFuncIndex(Value *Addr,
594655 const DataLayout &DL) {
595656 Type *OrigPtrTy = Addr->getType();
0 ; Test basic EfficiencySanitizer struct field count instrumentation.
1 ;
2 ; RUN: opt < %s -esan -esan-cache-frag -esan-instrument-loads-and-stores=false -esan-instrument-memintrinsics=false -S | FileCheck %s
3
4 %struct.A = type { i32, i32 }
5 %union.U = type { double }
6 %struct.C = type { %struct.anon, %union.anon, [10 x i8] }
7 %struct.anon = type { i32, i32 }
8 %union.anon = type { double }
9
10 define i32 @main() {
11 entry:
12 %a = alloca %struct.A, align 4
13 %u = alloca %union.U, align 8
14 %c = alloca [2 x %struct.C], align 16
15 %k = alloca %struct.A*, align 8
16 %x = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 0
17 %y = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 1
18 %f = bitcast %union.U* %u to float*
19 %d = bitcast %union.U* %u to double*
20 %arrayidx = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0
21 %cs = getelementptr inbounds %struct.C, %struct.C* %arrayidx, i32 0, i32 0
22 %x1 = getelementptr inbounds %struct.anon, %struct.anon* %cs, i32 0, i32 0
23 %arrayidx2 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 1
24 %cs3 = getelementptr inbounds %struct.C, %struct.C* %arrayidx2, i32 0, i32 0
25 %y4 = getelementptr inbounds %struct.anon, %struct.anon* %cs3, i32 0, i32 1
26 %arrayidx5 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0
27 %cu = getelementptr inbounds %struct.C, %struct.C* %arrayidx5, i32 0, i32 1
28 %f6 = bitcast %union.anon* %cu to float*
29 %arrayidx7 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 1
30 %cu8 = getelementptr inbounds %struct.C, %struct.C* %arrayidx7, i32 0, i32 1
31 %d9 = bitcast %union.anon* %cu8 to double*
32 %arrayidx10 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0
33 %c11 = getelementptr inbounds %struct.C, %struct.C* %arrayidx10, i32 0, i32 2
34 %arrayidx12 = getelementptr inbounds [10 x i8], [10 x i8]* %c11, i64 0, i64 2
35 %k1 = load %struct.A*, %struct.A** %k, align 8
36 %arrayidx13 = getelementptr inbounds %struct.A, %struct.A* %k1, i64 0
37 ret i32 0
38 }
39
40 ; CHECK: @llvm.global_ctors = {{.*}}@esan.module_ctor
41
42 ; CHECK: %a = alloca %struct.A, align 4
43 ; CHECK-NEXT: %u = alloca %union.U, align 8
44 ; CHECK-NEXT: %c = alloca [2 x %struct.C], align 16
45 ; CHECK-NEXT: %k = alloca %struct.A*, align 8
46 ; CHECK-NEXT: %0 = load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"struct.A#2#11#11", i32 0, i32 0)
47 ; CHECK-NEXT: %1 = add i64 %0, 1
48 ; CHECK-NEXT: store i64 %1, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"struct.A#2#11#11", i32 0, i32 0)
49 ; CHECK-NEXT: %x = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 0
50 ; CHECK-NEXT: %2 = load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"struct.A#2#11#11", i32 0, i32 1)
51 ; CHECK-NEXT: %3 = add i64 %2, 1
52 ; CHECK-NEXT: store i64 %3, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"struct.A#2#11#11", i32 0, i32 1)
53 ; CHECK-NEXT: %y = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 1
54 ; CHECK-NEXT: %f = bitcast %union.U* %u to float*
55 ; CHECK-NEXT: %d = bitcast %union.U* %u to double*
56 ; CHECK-NEXT: %arrayidx = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0
57 ; CHECK-NEXT: %4 = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.C#3#14#13#13", i32 0, i32 0)
58 ; CHECK-NEXT: %5 = add i64 %4, 1
59 ; CHECK-NEXT: store i64 %5, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.C#3#14#13#13", i32 0, i32 0)
60 ; CHECK-NEXT: %cs = getelementptr inbounds %struct.C, %struct.C* %arrayidx, i32 0, i32 0
61 ; CHECK-NEXT: %6 = load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"struct.anon#2#11#11", i32 0, i32 0)
62 ; CHECK-NEXT: %7 = add i64 %6, 1
63 ; CHECK-NEXT: store i64 %7, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"struct.anon#2#11#11", i32 0, i32 0)
64 ; CHECK-NEXT: %x1 = getelementptr inbounds %struct.anon, %struct.anon* %cs, i32 0, i32 0
65 ; CHECK-NEXT: %arrayidx2 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 1
66 ; CHECK-NEXT: %8 = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.C#3#14#13#13", i32 0, i32 0)
67 ; CHECK-NEXT: %9 = add i64 %8, 1
68 ; CHECK-NEXT: store i64 %9, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.C#3#14#13#13", i32 0, i32 0)
69 ; CHECK-NEXT: %cs3 = getelementptr inbounds %struct.C, %struct.C* %arrayidx2, i32 0, i32 0
70 ; CHECK-NEXT: %10 = load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"struct.anon#2#11#11", i32 0, i32 1)
71 ; CHECK-NEXT: %11 = add i64 %10, 1
72 ; CHECK-NEXT: store i64 %11, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"struct.anon#2#11#11", i32 0, i32 1)
73 ; CHECK-NEXT: %y4 = getelementptr inbounds %struct.anon, %struct.anon* %cs3, i32 0, i32 1
74 ; CHECK-NEXT: %arrayidx5 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0
75 ; CHECK-NEXT: %12 = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.C#3#14#13#13", i32 0, i32 1)
76 ; CHECK-NEXT: %13 = add i64 %12, 1
77 ; CHECK-NEXT: store i64 %13, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.C#3#14#13#13", i32 0, i32 1)
78 ; CHECK-NEXT: %cu = getelementptr inbounds %struct.C, %struct.C* %arrayidx5, i32 0, i32 1
79 ; CHECK-NEXT: %f6 = bitcast %union.anon* %cu to float*
80 ; CHECK-NEXT: %arrayidx7 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 1
81 ; CHECK-NEXT: %14 = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.C#3#14#13#13", i32 0, i32 1)
82 ; CHECK-NEXT: %15 = add i64 %14, 1
83 ; CHECK-NEXT: store i64 %15, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.C#3#14#13#13", i32 0, i32 1)
84 ; CHECK-NEXT: %cu8 = getelementptr inbounds %struct.C, %struct.C* %arrayidx7, i32 0, i32 1
85 ; CHECK-NEXT: %d9 = bitcast %union.anon* %cu8 to double*
86 ; CHECK-NEXT: %arrayidx10 = getelementptr inbounds [2 x %struct.C], [2 x %struct.C]* %c, i64 0, i64 0
87 ; CHECK-NEXT: %16 = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.C#3#14#13#13", i32 0, i32 2)
88 ; CHECK-NEXT: %17 = add i64 %16, 1
89 ; CHECK-NEXT: store i64 %17, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.C#3#14#13#13", i32 0, i32 2)
90 ; CHECK-NEXT: %c11 = getelementptr inbounds %struct.C, %struct.C* %arrayidx10, i32 0, i32 2
91 ; CHECK-NEXT: %arrayidx12 = getelementptr inbounds [10 x i8], [10 x i8]* %c11, i64 0, i64 2
92 ; CHECK-NEXT: %k1 = load %struct.A*, %struct.A** %k, align 8
93 ; CHECK-NEXT: %arrayidx13 = getelementptr inbounds %struct.A, %struct.A* %k1, i64 0
94 ; CHECK-NEXT: ret i32 0