Index: lib/Transforms/Instrumentation/EfficiencySanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/EfficiencySanitizer.cpp +++ lib/Transforms/Instrumentation/EfficiencySanitizer.cpp @@ -30,6 +30,7 @@ #include "llvm/IR/Type.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/ModuleUtils.h" @@ -61,6 +62,7 @@ STATISTIC(NumFastpaths, "Number of instrumented fastpaths"); STATISTIC(NumAccessesWithIrregularSize, "Number of accesses with a size outside our targeted callout sizes"); +STATISTIC(NumIgnoredStructs, "Number of ignored structs"); static const uint64_t EsanCtorAndDtorPriority = 0; static const char *const EsanModuleCtorName = "esan.module_ctor"; @@ -85,6 +87,10 @@ 6, // ESAN_WorkingSet: 64B:1B, so 64 to 1 == >>6. }; +// MaxStructCounterNameSize is a soft size limit to avoid insanely long +// names for those extremely large structs. +static const unsigned MaxStructCounterNameSize = 512; + namespace { static EfficiencySanitizerOptions @@ -130,6 +136,9 @@ private: bool initOnModule(Module &M); void initializeCallbacks(Module &M); + bool shouldIgnoreStructType(StructType *StructTy); + void createStructCounterName( + StructType *StructTy, SmallString &NameStr); GlobalVariable *createCacheFragInfoGV(Module &M, Constant *UnitName); Constant *createEsanInitToolInfoArg(Module &M); void createDestructor(Module &M, Constant *ToolInfoArg); @@ -220,6 +229,39 @@ IRB.getInt32Ty(), IntptrTy, nullptr)); } +bool EfficiencySanitizer::shouldIgnoreStructType(StructType *StructTy) { + if (StructTy == nullptr || StructTy->isOpaque() /* no struct body */) + return true; + return false; +} + +void EfficiencySanitizer::createStructCounterName( + StructType *StructTy, SmallString &NameStr) { + // Append NumFields and field type ids to avoid struct conflicts + // with the same name but different fields. + if (StructTy->hasName()) + NameStr += StructTy->getName(); + else + NameStr += "struct.anon"; + // We allow the actual size of the StructCounterName to be larger than + // MaxStructCounterNameSize and append #NumFields and at least one + // field type id. + // Append #NumFields. + NameStr += "#"; + Twine(StructTy->getNumElements()).toVector(NameStr); + // Append struct field type ids in the reverse order. + for (int i = StructTy->getNumElements() - 1; i >= 0; --i) { + NameStr += "#"; + Twine(StructTy->getElementType(i)->getTypeID()).toVector(NameStr); + if (NameStr.size() >= MaxStructCounterNameSize) + break; + } + if (StructTy->isLiteral()) { + // End with # for literal struct. + NameStr += "#"; + } +} + // Create the global variable for the cache-fragmentation tool. GlobalVariable *EfficiencySanitizer::createCacheFragInfoGV( Module &M, Constant *UnitName) { @@ -228,12 +270,13 @@ auto *Int8PtrTy = Type::getInt8PtrTy(*Ctx); auto *Int8PtrPtrTy = Int8PtrTy->getPointerTo(); auto *Int32Ty = Type::getInt32Ty(*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 NumOfFields; + // u32 NumFields; // u64 *FieldCounters; // const char **FieldTypeNames; // }; @@ -244,20 +287,87 @@ // in the runtime library. // struct CacheFragInfo { // const char *UnitName; - // u32 NumOfStructs; + // u32 NumStructs; // StructInfo *Structs; // }; auto *CacheFragInfoTy = StructType::get(Int8PtrTy, Int32Ty, StructInfoPtrTy, nullptr); std::vector Vec = M.getIdentifiedStructTypes(); - // FIXME: iterate over Vec and create the StructInfo array. + unsigned NumStructs = 0; + SmallVector Initializers; + + for (auto &StructTy : Vec) { + if (shouldIgnoreStructType(StructTy)) { + ++NumIgnoredStructs; + continue; + } + ++NumStructs; + + // StructName. + SmallString CounterNameStr; + createStructCounterName(StructTy, CounterNameStr); + GlobalVariable *StructCounterName = createPrivateGlobalForString( + M, CounterNameStr, /*AllowMerging*/true); + + // FieldCounters. + // We create the counter array with StructCounterName and weak linkage + // so that the structs with the same name and layout from different + // compilation units will be merged into one. + auto *CounterArrayTy = ArrayType::get(Int64Ty, StructTy->getNumElements()); + GlobalVariable *Counters = + new GlobalVariable(M, CounterArrayTy, false, + GlobalVariable::WeakAnyLinkage, + ConstantAggregateZero::get(CounterArrayTy), + CounterNameStr); + + // FieldTypeNames. + // We pass the field type name array to the runtime for better reporting. + auto *TypeNameArrayTy = ArrayType::get(Int8PtrTy, StructTy->getNumElements()); + GlobalVariable *TypeName = + new GlobalVariable(M, TypeNameArrayTy, true, + GlobalVariable::InternalLinkage, nullptr); + SmallVector TypeNameVec; + for (unsigned i = 0; i < StructTy->getNumElements(); ++i) { + Type *Ty = StructTy->getElementType(i); + std::string Str; + raw_string_ostream StrOS(Str); + Ty->print(StrOS); + TypeNameVec.push_back( + ConstantExpr::getPointerCast( + createPrivateGlobalForString(M, StrOS.str(), true), + Int8PtrTy)); + } + TypeName->setInitializer(ConstantArray::get(TypeNameArrayTy, TypeNameVec)); + + Initializers.push_back( + ConstantStruct::get( + StructInfoTy, + ConstantExpr::getPointerCast(StructCounterName, Int8PtrTy), + ConstantInt::get(Int32Ty, StructTy->getNumElements()), + ConstantExpr::getPointerCast(Counters, Int64PtrTy), + ConstantExpr::getPointerCast(TypeName, Int8PtrPtrTy), + nullptr)); + } + // Structs. + Constant *StructInfo; + if (NumStructs == 0) { + StructInfo = ConstantPointerNull::get(StructInfoPtrTy); + } else { + auto *StructInfoArrayTy = ArrayType::get(StructInfoTy, NumStructs); + StructInfo = ConstantExpr::getPointerCast( + new GlobalVariable(M, StructInfoArrayTy, false, + GlobalVariable::InternalLinkage, + ConstantArray::get(StructInfoArrayTy, Initializers)), + StructInfoPtrTy); + } + auto *CacheFragInfoGV = new GlobalVariable( M, CacheFragInfoTy, true, GlobalVariable::InternalLinkage, ConstantStruct::get(CacheFragInfoTy, UnitName, - ConstantInt::get(Int32Ty, Vec.size()), - ConstantPointerNull::get(StructInfoPtrTy), + ConstantInt::get(Int32Ty, NumStructs), + StructInfo, nullptr)); return CacheFragInfoGV; }