diff options
| -rw-r--r-- | llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp | 40 | ||||
| -rw-r--r-- | llvm/test/Instrumentation/EfficiencySanitizer/struct_field_count_basic.ll | 39 | 
2 files changed, 66 insertions, 13 deletions
diff --git a/llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp index 63391b373c5..83ae3d516f8 100644 --- a/llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp @@ -158,8 +158,9 @@ private:    bool shouldIgnoreStructType(StructType *StructTy);    void createStructCounterName(        StructType *StructTy, SmallString<MaxStructCounterNameSize> &NameStr); -  GlobalVariable *createCacheFragInfoGV(Module &M, Constant *UnitName); -  Constant *createEsanInitToolInfoArg(Module &M); +  GlobalVariable *createCacheFragInfoGV(Module &M, const DataLayout &DL, +                                        Constant *UnitName); +  Constant *createEsanInitToolInfoArg(Module &M, const DataLayout &DL);    void createDestructor(Module &M, Constant *ToolInfoArg);    bool runOnFunction(Function &F, Module &M);    bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL); @@ -287,24 +288,28 @@ void EfficiencySanitizer::createStructCounterName(  // Create the global variable for the cache-fragmentation tool.  GlobalVariable *EfficiencySanitizer::createCacheFragInfoGV( -    Module &M, Constant *UnitName) { +    Module &M, const DataLayout &DL, Constant *UnitName) {    assert(Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag);    auto *Int8PtrTy = Type::getInt8PtrTy(*Ctx);    auto *Int8PtrPtrTy = Int8PtrTy->getPointerTo();    auto *Int32Ty = Type::getInt32Ty(*Ctx); +  auto *Int32PtrTy = Type::getInt32PtrTy(*Ctx);    auto *Int64Ty = Type::getInt64Ty(*Ctx);    auto *Int64PtrTy = Type::getInt64PtrTy(*Ctx);    // This structure should be kept consistent with the StructInfo struct    // in the runtime library.    // struct StructInfo {    //   const char *StructName; +  //   u32 Size;    //   u32 NumFields; +  //   u32 *FieldOffsets;    //   u64 *FieldCounters;    //   const char **FieldTypeNames;    // };    auto *StructInfoTy = -    StructType::get(Int8PtrTy, Int32Ty, Int64PtrTy, Int8PtrPtrTy, nullptr); +    StructType::get(Int8PtrTy, Int32Ty, Int32Ty, Int32PtrTy, Int64PtrTy, +                    Int8PtrPtrTy, nullptr);    auto *StructInfoPtrTy = StructInfoTy->getPointerTo();    // This structure should be kept consistent with the CacheFragInfo struct    // in the runtime library. @@ -347,13 +352,21 @@ GlobalVariable *EfficiencySanitizer::createCacheFragInfoGV(      // Remember the counter variable for each struct type.      StructTyMap.insert(std::pair<Type *, GlobalVariable *>(StructTy, Counters)); +    // We pass the field type name array and offset array to the runtime for +    // better reporting.      // FieldTypeNames. -    // We pass the field type name array to the runtime for better reporting.      auto *TypeNameArrayTy = ArrayType::get(Int8PtrTy, StructTy->getNumElements()); -    GlobalVariable *TypeName = +    GlobalVariable *TypeNames =        new GlobalVariable(M, TypeNameArrayTy, true,                           GlobalVariable::InternalLinkage, nullptr);      SmallVector<Constant *, 16> TypeNameVec; +    // FieldOffsets. +    const StructLayout *SL = DL.getStructLayout(StructTy); +    auto *OffsetArrayTy = ArrayType::get(Int32Ty, StructTy->getNumElements()); +    GlobalVariable *Offsets = +      new GlobalVariable(M, OffsetArrayTy, true, +                         GlobalVariable::InternalLinkage, nullptr); +    SmallVector<Constant *, 16> OffsetVec;      for (unsigned i = 0; i < StructTy->getNumElements(); ++i) {        Type *Ty = StructTy->getElementType(i);        std::string Str; @@ -363,16 +376,20 @@ GlobalVariable *EfficiencySanitizer::createCacheFragInfoGV(            ConstantExpr::getPointerCast(                createPrivateGlobalForString(M, StrOS.str(), true),                Int8PtrTy)); +      OffsetVec.push_back(ConstantInt::get(Int32Ty, SL->getElementOffset(i)));      } -    TypeName->setInitializer(ConstantArray::get(TypeNameArrayTy, TypeNameVec)); +    TypeNames->setInitializer(ConstantArray::get(TypeNameArrayTy, TypeNameVec)); +    Offsets->setInitializer(ConstantArray::get(OffsetArrayTy, OffsetVec));      Initializers.push_back(          ConstantStruct::get(              StructInfoTy,              ConstantExpr::getPointerCast(StructCounterName, Int8PtrTy), +            ConstantInt::get(Int32Ty, SL->getSizeInBytes()),              ConstantInt::get(Int32Ty, StructTy->getNumElements()), +            ConstantExpr::getPointerCast(Offsets, Int32PtrTy),              ConstantExpr::getPointerCast(Counters, Int64PtrTy), -            ConstantExpr::getPointerCast(TypeName, Int8PtrPtrTy), +            ConstantExpr::getPointerCast(TypeNames, Int8PtrPtrTy),              nullptr));    }    // Structs. @@ -399,7 +416,8 @@ GlobalVariable *EfficiencySanitizer::createCacheFragInfoGV(  }  // Create the tool-specific argument passed to EsanInit and EsanExit. -Constant *EfficiencySanitizer::createEsanInitToolInfoArg(Module &M) { +Constant *EfficiencySanitizer::createEsanInitToolInfoArg(Module &M, +                                                         const DataLayout &DL) {    // This structure contains tool-specific information about each compilation    // unit (module) and is passed to the runtime library.    GlobalVariable *ToolInfoGV = nullptr; @@ -412,7 +430,7 @@ Constant *EfficiencySanitizer::createEsanInitToolInfoArg(Module &M) {    // Create the tool-specific variable.    if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag) -    ToolInfoGV = createCacheFragInfoGV(M, UnitName); +    ToolInfoGV = createCacheFragInfoGV(M, DL, UnitName);    if (ToolInfoGV != nullptr)      return ConstantExpr::getPointerCast(ToolInfoGV, Int8PtrTy); @@ -445,7 +463,7 @@ bool EfficiencySanitizer::initOnModule(Module &M) {    PointerType *Int8PtrTy = Type::getInt8PtrTy(*Ctx);    IntptrTy = DL.getIntPtrType(M.getContext());    // Create the variable passed to EsanInit and EsanExit. -  Constant *ToolInfoArg = createEsanInitToolInfoArg(M); +  Constant *ToolInfoArg = createEsanInitToolInfoArg(M, DL);    // Constructor    // We specify the tool type both in the EsanWhichToolName global    // and as an arg to the init routine as a sanity check. diff --git a/llvm/test/Instrumentation/EfficiencySanitizer/struct_field_count_basic.ll b/llvm/test/Instrumentation/EfficiencySanitizer/struct_field_count_basic.ll index 5cc5f062230..807f28df913 100644 --- a/llvm/test/Instrumentation/EfficiencySanitizer/struct_field_count_basic.ll +++ b/llvm/test/Instrumentation/EfficiencySanitizer/struct_field_count_basic.ll @@ -8,6 +8,40 @@  %struct.anon = type { i32, i32 }  %union.anon = type { double } +; CHECK:        @0 = private unnamed_addr constant [8 x i8] c"<stdin>\00", align 1 +; CHECK-NEXT:   @1 = private unnamed_addr constant [17 x i8] c"struct.A#2#11#11\00", align 1 +; CHECK-NEXT:   @"struct.A#2#11#11" = weak global [2 x i64] zeroinitializer +; CHECK-NEXT:   @2 = internal constant [2 x i8*] [i8* getelementptr inbounds ([4 x i8], [4 x i8]* @4, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @5, i32 0, i32 0)] +; CHECK-NEXT:   @3 = internal constant [2 x i32] [i32 0, i32 4] +; CHECK-NEXT:   @4 = private unnamed_addr constant [4 x i8] c"i32\00", align 1 +; CHECK-NEXT:   @5 = private unnamed_addr constant [4 x i8] c"i32\00", align 1 +; CHECK-NEXT:   @6 = private unnamed_addr constant [12 x i8] c"union.U#1#3\00", align 1 +; CHECK-NEXT:   @"union.U#1#3" = weak global [1 x i64] zeroinitializer +; CHECK-NEXT:   @7 = internal constant [1 x i8*] [i8* getelementptr inbounds ([7 x i8], [7 x i8]* @9, i32 0, i32 0)] +; CHECK-NEXT:   @8 = internal constant [1 x i32] zeroinitializer +; CHECK-NEXT:   @9 = private unnamed_addr constant [7 x i8] c"double\00", align 1 +; CHECK-NEXT:   @10 = private unnamed_addr constant [20 x i8] c"struct.C#3#14#13#13\00", align 1 +; CHECK-NEXT:   @"struct.C#3#14#13#13" = weak global [3 x i64] zeroinitializer +; CHECK-NEXT:   @11 = internal constant [3 x i8*] [i8* getelementptr inbounds ([33 x i8], [33 x i8]* @13, i32 0, i32 0), i8* getelementptr inbounds ([30 x i8], [30 x i8]* @14, i32 0, i32 0), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @15, i32 0, i32 0)] +; CHECK-NEXT:   @12 = internal constant [3 x i32] [i32 0, i32 8, i32 16] +; CHECK-NEXT:   @13 = private unnamed_addr constant [33 x i8] c"%struct.anon = type { i32, i32 }\00", align 1 +; CHECK-NEXT:   @14 = private unnamed_addr constant [30 x i8] c"%union.anon = type { double }\00", align 1 +; CHECK-NEXT:   @15 = private unnamed_addr constant [10 x i8] c"[10 x i8]\00", align 1 +; CHECK-NEXT:   @16 = private unnamed_addr constant [20 x i8] c"struct.anon#2#11#11\00", align 1 +; CHECK-NEXT:   @"struct.anon#2#11#11" = weak global [2 x i64] zeroinitializer +; CHECK-NEXT:   @17 = internal constant [2 x i8*] [i8* getelementptr inbounds ([4 x i8], [4 x i8]* @19, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @20, i32 0, i32 0)] +; CHECK-NEXT:   @18 = internal constant [2 x i32] [i32 0, i32 4] +; CHECK-NEXT:   @19 = private unnamed_addr constant [4 x i8] c"i32\00", align 1 +; CHECK-NEXT:   @20 = private unnamed_addr constant [4 x i8] c"i32\00", align 1 +; CHECK-NEXT:   @21 = private unnamed_addr constant [15 x i8] c"union.anon#1#3\00", align 1 +; CHECK-NEXT:   @"union.anon#1#3" = weak global [1 x i64] zeroinitializer +; CHECK-NEXT:   @22 = internal constant [1 x i8*] [i8* getelementptr inbounds ([7 x i8], [7 x i8]* @24, i32 0, i32 0)] +; CHECK-NEXT:   @23 = internal constant [1 x i32] zeroinitializer +; CHECK-NEXT:   @24 = private unnamed_addr constant [7 x i8] c"double\00", align 1 +; CHECK-NEXT:   @25 = internal global [5 x { i8*, i32, i32, i32*, i64*, i8** }] [{ i8*, i32, i32, i32*, i64*, i8** } { i8* getelementptr inbounds ([17 x i8], [17 x i8]* @1, i32 0, i32 0), i32 8, i32 2, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @3, i32 0, i32 0), i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"struct.A#2#11#11", i32 0, i32 0), i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @2, i32 0, i32 0) }, { i8*, i32, i32, i32*, i64*, i8** } { i8* getelementptr inbounds ([12 x i8], [12 x i8]* @6, i32 0, i32 0), i32 8, i32 1, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @8, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"union.U#1#3", i32 0, i32 0), i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @7, i32 0, i32 0) }, { i8*, i32, i32, i32*, i64*, i8** } { i8* getelementptr inbounds ([20 x i8], [20 x i8]* @10, i32 0, i32 0), i32 32, i32 3, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @12, i32 0, i32 0), i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.C#3#14#13#13", i32 0, i32 0), i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @11, i32 0, i32 0) }, { i8*, i32, i32, i32*, i64*, i8** } { i8* getelementptr inbounds ([20 x i8], [20 x i8]* @16, i32 0, i32 0), i32 8, i32 2, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @18, i32 0, i32 0), i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"struct.anon#2#11#11", i32 0, i32 0), i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @17, i32 0, i32 0) }, { i8*, i32, i32, i32*, i64*, i8** } { i8* getelementptr inbounds ([15 x i8], [15 x i8]* @21, i32 0, i32 0), i32 8, i32 1, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @23, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"union.anon#1#3", i32 0, i32 0), i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @22, i32 0, i32 0) }] +; CHECK-NEXT:   @26 = internal constant { i8*, i32, { i8*, i32, i32, i32*, i64*, i8** }* } { i8* getelementptr inbounds ([8 x i8], [8 x i8]* @0, i32 0, i32 0), i32 5, { i8*, i32, i32, i32*, i64*, i8** }* getelementptr inbounds ([5 x { i8*, i32, i32, i32*, i64*, i8** }], [5 x { i8*, i32, i32, i32*, i64*, i8** }]* @25, i32 0, i32 0) } + +  define i32 @main() {  entry:    %a = alloca %struct.A, align 4 @@ -39,6 +73,7 @@ entry:  }  ; CHECK: @llvm.global_ctors = {{.*}}@esan.module_ctor +; CHECK: @llvm.global_dtors = {{.*}}@esan.module_dtor  ; CHECK:        %a = alloca %struct.A, align 4  ; CHECK-NEXT:   %u = alloca %union.U, align 8 @@ -98,6 +133,6 @@ entry:  ; Top-level:  ; CHECK: define internal void @esan.module_ctor() -; CHECK: call void @__esan_init(i32 1, i8* bitcast ({ i8*, i32, { i8*, i32, i64*, i8** }* }* @21 to i8*)) +; CHECK: call void @__esan_init(i32 1, i8* bitcast ({ i8*, i32, { i8*, i32, i32, i32*, i64*, i8** }* }* @26 to i8*))  ; CHECK: define internal void @esan.module_dtor() -; CHECK: call void @__esan_exit(i8* bitcast ({ i8*, i32, { i8*, i32, i64*, i8** }* }* @21 to i8*)) +; CHECK: call void @__esan_exit(i8* bitcast ({ i8*, i32, { i8*, i32, i32, i32*, i64*, i8** }* }* @26 to i8*))  | 

