diff options
Diffstat (limited to 'llvm/lib/Transforms/Instrumentation')
5 files changed, 154 insertions, 55 deletions
| diff --git a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp index 5ba2167..cc53ec2 100644 --- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp @@ -1957,8 +1957,12 @@ Value *DataFlowSanitizer::getShadowAddress(Value *Addr,  Value *DataFlowSanitizer::getShadowAddress(Value *Addr,                                             BasicBlock::iterator Pos) {    IRBuilder<> IRB(Pos->getParent(), Pos); -  Value *ShadowOffset = getShadowOffset(Addr, IRB); -  return getShadowAddress(Addr, Pos, ShadowOffset); +  Value *ShadowAddr = getShadowOffset(Addr, IRB); +  uint64_t ShadowBase = MapParams->ShadowBase; +  if (ShadowBase != 0) +    ShadowAddr = +        IRB.CreateAdd(ShadowAddr, ConstantInt::get(IntptrTy, ShadowBase)); +  return getShadowAddress(Addr, Pos, ShadowAddr);  }  Value *DFSanFunction::combineShadowsThenConvert(Type *T, Value *V1, Value *V2, diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp index 7795cce..b5548d4 100644 --- a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -69,14 +69,6 @@ namespace llvm {  // Command line option to enable vtable value profiling. Defined in  // ProfileData/InstrProf.cpp: -enable-vtable-value-profiling=  extern cl::opt<bool> EnableVTableValueProfiling; -// TODO: Remove -debug-info-correlate in next LLVM release, in favor of -// -profile-correlate=debug-info. -cl::opt<bool> DebugInfoCorrelate( -    "debug-info-correlate", -    cl::desc("Use debug info to correlate profiles. (Deprecated, use " -             "-profile-correlate=debug-info)"), -    cl::init(false)); -  LLVM_ABI cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate(      "profile-correlate",      cl::desc("Use debug info or binary file to correlate profiles."), @@ -1047,7 +1039,7 @@ void InstrLowerer::lowerValueProfileInst(InstrProfValueProfileInst *Ind) {    // in lightweight mode. We need to move the value profile pointer to the    // Counter struct to get this working.    assert( -      !DebugInfoCorrelate && ProfileCorrelate == InstrProfCorrelator::NONE && +      ProfileCorrelate == InstrProfCorrelator::NONE &&        "Value profiling is not yet supported with lightweight instrumentation");    GlobalVariable *Name = Ind->getName();    auto It = ProfileDataMap.find(Name); @@ -1504,7 +1496,7 @@ static inline Constant *getVTableAddrForProfData(GlobalVariable *GV) {  }  void InstrLowerer::getOrCreateVTableProfData(GlobalVariable *GV) { -  assert(!DebugInfoCorrelate && +  assert(ProfileCorrelate != InstrProfCorrelator::DEBUG_INFO &&           "Value profiling is not supported with lightweight instrumentation");    if (GV->isDeclaration() || GV->hasAvailableExternallyLinkage())      return; @@ -1584,8 +1576,7 @@ GlobalVariable *InstrLowerer::setupProfileSection(InstrProfInstBase *Inc,    // Use internal rather than private linkage so the counter variable shows up    // in the symbol table when using debug info for correlation. -  if ((DebugInfoCorrelate || -       ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO) && +  if (ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO &&        TT.isOSBinFormatMachO() && Linkage == GlobalValue::PrivateLinkage)      Linkage = GlobalValue::InternalLinkage; @@ -1691,8 +1682,7 @@ InstrLowerer::getOrCreateRegionCounters(InstrProfCntrInstBase *Inc) {    auto *CounterPtr = setupProfileSection(Inc, IPSK_cnts);    PD.RegionCounters = CounterPtr; -  if (DebugInfoCorrelate || -      ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO) { +  if (ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO) {      LLVMContext &Ctx = M.getContext();      Function *Fn = Inc->getParent()->getParent();      if (auto *SP = Fn->getSubprogram()) { @@ -1737,7 +1727,7 @@ InstrLowerer::getOrCreateRegionCounters(InstrProfCntrInstBase *Inc) {  void InstrLowerer::createDataVariable(InstrProfCntrInstBase *Inc) {    // When debug information is correlated to profile data, a data variable    // is not needed. -  if (DebugInfoCorrelate || ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO) +  if (ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO)      return;    GlobalVariable *NamePtr = Inc->getName(); diff --git a/llvm/lib/Transforms/Instrumentation/MemProfUse.cpp b/llvm/lib/Transforms/Instrumentation/MemProfUse.cpp index a6ec6c1..b72d41a 100644 --- a/llvm/lib/Transforms/Instrumentation/MemProfUse.cpp +++ b/llvm/lib/Transforms/Instrumentation/MemProfUse.cpp @@ -127,15 +127,19 @@ static uint64_t computeStackId(const memprof::Frame &Frame) {    return computeStackId(Frame.Function, Frame.LineOffset, Frame.Column);  } +static AllocationType getAllocType(const AllocationInfo *AllocInfo) { +  return getAllocType(AllocInfo->Info.getTotalLifetimeAccessDensity(), +                      AllocInfo->Info.getAllocCount(), +                      AllocInfo->Info.getTotalLifetime()); +} +  static AllocationType addCallStack(CallStackTrie &AllocTrie,                                     const AllocationInfo *AllocInfo,                                     uint64_t FullStackId) {    SmallVector<uint64_t> StackIds;    for (const auto &StackFrame : AllocInfo->CallStack)      StackIds.push_back(computeStackId(StackFrame)); -  auto AllocType = getAllocType(AllocInfo->Info.getTotalLifetimeAccessDensity(), -                                AllocInfo->Info.getAllocCount(), -                                AllocInfo->Info.getTotalLifetime()); +  auto AllocType = getAllocType(AllocInfo);    std::vector<ContextTotalSize> ContextSizeInfo;    if (recordContextSizeInfoForAnalysis()) {      auto TotalSize = AllocInfo->Info.getTotalSize(); @@ -216,7 +220,6 @@ static void HandleUnsupportedAnnotationKinds(GlobalVariable &GVar,    }    LLVM_DEBUG(dbgs() << "Skip annotation for " << GVar.getName() << " due to "                      << Reason << ".\n"); -  return;  }  struct AllocMatchInfo { @@ -406,22 +409,39 @@ handleAllocSite(Instruction &I, CallBase *CI,                  const std::set<const AllocationInfo *> &AllocInfoSet,                  std::map<std::pair<uint64_t, unsigned>, AllocMatchInfo>                      &FullStackIdToAllocMatchInfo) { +  // TODO: Remove this once the profile creation logic deduplicates contexts +  // that are the same other than the IsInlineFrame bool. Until then, keep the +  // largest. +  DenseMap<uint64_t, const AllocationInfo *> UniqueFullContextIdAllocInfo; +  for (auto *AllocInfo : AllocInfoSet) { +    auto FullStackId = computeFullStackId(AllocInfo->CallStack); +    auto [It, Inserted] = +        UniqueFullContextIdAllocInfo.insert({FullStackId, AllocInfo}); +    // If inserted entry, done. +    if (Inserted) +      continue; +    // Keep the larger one, or the noncold one if they are the same size. +    auto CurSize = It->second->Info.getTotalSize(); +    auto NewSize = AllocInfo->Info.getTotalSize(); +    if ((CurSize > NewSize) || +        (CurSize == NewSize && +         getAllocType(AllocInfo) != AllocationType::NotCold)) +      continue; +    It->second = AllocInfo; +  }    // We may match this instruction's location list to multiple MIB    // contexts. Add them to a Trie specialized for trimming the contexts to    // the minimal needed to disambiguate contexts with unique behavior.    CallStackTrie AllocTrie(&ORE, MaxColdSize);    uint64_t TotalSize = 0;    uint64_t TotalColdSize = 0; -  for (auto *AllocInfo : AllocInfoSet) { +  for (auto &[FullStackId, AllocInfo] : UniqueFullContextIdAllocInfo) {      // Check the full inlined call stack against this one.      // If we found and thus matched all frames on the call, include      // this MIB.      if (stackFrameIncludesInlinedCallStack(AllocInfo->CallStack,                                             InlinedCallStack)) {        NumOfMemProfMatchedAllocContexts++; -      uint64_t FullStackId = 0; -      if (ClPrintMemProfMatchInfo || recordContextSizeInfoForAnalysis()) -        FullStackId = computeFullStackId(AllocInfo->CallStack);        auto AllocType = addCallStack(AllocTrie, AllocInfo, FullStackId);        TotalSize += AllocInfo->Info.getTotalSize();        if (AllocType == AllocationType::Cold) diff --git a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp index 71736cf..af53fa0 100644 --- a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -456,7 +456,7 @@ createIRLevelProfileFlagVar(Module &M,      ProfileVersion |= VARIANT_MASK_INSTR_ENTRY;    if (PGOInstrumentLoopEntries)      ProfileVersion |= VARIANT_MASK_INSTR_LOOP_ENTRIES; -  if (DebugInfoCorrelate || ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO) +  if (ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO)      ProfileVersion |= VARIANT_MASK_DBG_CORRELATE;    if (PGOFunctionEntryCoverage)      ProfileVersion |= diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp index 78d4a57e..87eba5f 100644 --- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp @@ -58,6 +58,18 @@ static cl::opt<bool>                            cl::desc("Writes always set the type"), cl::Hidden,                            cl::init(false)); +static cl::opt<bool> ClOutlineInstrumentation( +    "tysan-outline-instrumentation", +    cl::desc("Uses function calls for all TySan instrumentation, reducing " +             "ELF size"), +    cl::Hidden, cl::init(false)); + +static cl::opt<bool> ClVerifyOutlinedInstrumentation( +    "tysan-verify-outlined-instrumentation", +    cl::desc("Check types twice with both inlined instrumentation and " +             "function calls. This verifies that they behave the same."), +    cl::Hidden, cl::init(false)); +  STATISTIC(NumInstrumentedAccesses, "Number of instrumented accesses");  namespace { @@ -105,12 +117,16 @@ private:    Regex AnonNameRegex;    Type *IntptrTy;    uint64_t PtrShift; -  IntegerType *OrdTy; +  IntegerType *OrdTy, *U64Ty;    /// Callbacks to run-time library are computed in initializeCallbacks.    FunctionCallee TysanCheck;    FunctionCallee TysanCtorFunction; +  FunctionCallee TysanIntrumentMemInst; +  FunctionCallee TysanInstrumentWithShadowUpdate; +  FunctionCallee TysanSetShadowType; +    /// Callback to set types for gloabls.    Function *TysanGlobalsSetTypeFunction;  }; @@ -130,6 +146,8 @@ TypeSanitizer::TypeSanitizer(Module &M)  void TypeSanitizer::initializeCallbacks(Module &M) {    IRBuilder<> IRB(M.getContext());    OrdTy = IRB.getInt32Ty(); +  U64Ty = IRB.getInt64Ty(); +  Type *BoolType = IRB.getInt1Ty();    AttributeList Attr;    Attr = Attr.addFnAttribute(M.getContext(), Attribute::NoUnwind); @@ -144,6 +162,30 @@ void TypeSanitizer::initializeCallbacks(Module &M) {    TysanCtorFunction =        M.getOrInsertFunction(kTysanModuleCtorName, Attr, IRB.getVoidTy()); + +  TysanIntrumentMemInst = M.getOrInsertFunction( +      "__tysan_instrument_mem_inst", Attr, IRB.getVoidTy(), +      IRB.getPtrTy(), // Pointer of data to be written to +      IRB.getPtrTy(), // Pointer of data to write +      U64Ty,          // Size of the data in bytes +      BoolType        // Do we need to call memmove +  ); + +  TysanInstrumentWithShadowUpdate = M.getOrInsertFunction( +      "__tysan_instrument_with_shadow_update", Attr, IRB.getVoidTy(), +      IRB.getPtrTy(), // Pointer to data to be read +      IRB.getPtrTy(), // Pointer to type descriptor +      BoolType,       // Do we need to type check this +      U64Ty,          // Size of data we access in bytes +      OrdTy           // Flags +  ); + +  TysanSetShadowType = M.getOrInsertFunction( +      "__tysan_set_shadow_type", Attr, IRB.getVoidTy(), +      IRB.getPtrTy(), // Pointer of data to be written to +      IRB.getPtrTy(), // Pointer to the new type descriptor +      U64Ty           // Size of data we access in bytes +  );  }  void TypeSanitizer::instrumentGlobals(Module &M) { @@ -587,6 +629,29 @@ bool TypeSanitizer::instrumentWithShadowUpdate(    Value *TD = IRB.CreateBitCast(TDGV, IRB.getPtrTy()); +  if (ClOutlineInstrumentation) { +    if (!ForceSetType && (!ClWritesAlwaysSetType || IsRead)) { +      // We need to check the type here. If the type is unknown, then the read +      // sets the type. If the type is known, then it is checked. If the type +      // doesn't match, then we call the runtime type check (which may yet +      // determine that the mismatch is okay). + +      Constant *Flags = +          ConstantInt::get(OrdTy, (int)IsRead | (((int)IsWrite) << 1)); + +      IRB.CreateCall(TysanInstrumentWithShadowUpdate, +                     {Ptr, TD, +                      SanitizeFunction ? IRB.getTrue() : IRB.getFalse(), +                      IRB.getInt64(AccessSize), Flags}); +    } else if (ForceSetType || IsWrite) { +      // In the mode where writes always set the type, for a write (which does +      // not also read), we just set the type. +      IRB.CreateCall(TysanSetShadowType, {Ptr, TD, IRB.getInt64(AccessSize)}); +    } + +    return true; +  } +    Value *ShadowDataInt = convertToShadowDataInt(IRB, Ptr, IntptrTy, PtrShift,                                                  ShadowBase, AppMemMask);    Type *Int8PtrPtrTy = PointerType::get(IRB.getContext(), 0); @@ -838,37 +903,47 @@ bool TypeSanitizer::instrumentMemInst(Value *V, Instruction *ShadowBase,      }    } -  if (!ShadowBase) -    ShadowBase = getShadowBase(*F); -  if (!AppMemMask) -    AppMemMask = getAppMemMask(*F); +  if (ClOutlineInstrumentation) { +    if (!Src) +      Src = ConstantPointerNull::get(IRB.getPtrTy()); -  Value *ShadowDataInt = IRB.CreateAdd( -      IRB.CreateShl( -          IRB.CreateAnd(IRB.CreatePtrToInt(Dest, IntptrTy), AppMemMask), -          PtrShift), -      ShadowBase); -  Value *ShadowData = IRB.CreateIntToPtr(ShadowDataInt, IRB.getPtrTy()); - -  if (!Src) { -    IRB.CreateMemSet(ShadowData, IRB.getInt8(0), IRB.CreateShl(Size, PtrShift), -                     Align(1ull << PtrShift)); +    IRB.CreateCall( +        TysanIntrumentMemInst, +        {Dest, Src, Size, NeedsMemMove ? IRB.getTrue() : IRB.getFalse()});      return true; -  } - -  Value *SrcShadowDataInt = IRB.CreateAdd( -      IRB.CreateShl( -          IRB.CreateAnd(IRB.CreatePtrToInt(Src, IntptrTy), AppMemMask), -          PtrShift), -      ShadowBase); -  Value *SrcShadowData = IRB.CreateIntToPtr(SrcShadowDataInt, IRB.getPtrTy()); - -  if (NeedsMemMove) { -    IRB.CreateMemMove(ShadowData, Align(1ull << PtrShift), SrcShadowData, -                      Align(1ull << PtrShift), IRB.CreateShl(Size, PtrShift));    } else { -    IRB.CreateMemCpy(ShadowData, Align(1ull << PtrShift), SrcShadowData, -                     Align(1ull << PtrShift), IRB.CreateShl(Size, PtrShift)); +    if (!ShadowBase) +      ShadowBase = getShadowBase(*F); +    if (!AppMemMask) +      AppMemMask = getAppMemMask(*F); + +    Value *ShadowDataInt = IRB.CreateAdd( +        IRB.CreateShl( +            IRB.CreateAnd(IRB.CreatePtrToInt(Dest, IntptrTy), AppMemMask), +            PtrShift), +        ShadowBase); +    Value *ShadowData = IRB.CreateIntToPtr(ShadowDataInt, IRB.getPtrTy()); + +    if (!Src) { +      IRB.CreateMemSet(ShadowData, IRB.getInt8(0), +                       IRB.CreateShl(Size, PtrShift), Align(1ull << PtrShift)); +      return true; +    } + +    Value *SrcShadowDataInt = IRB.CreateAdd( +        IRB.CreateShl( +            IRB.CreateAnd(IRB.CreatePtrToInt(Src, IntptrTy), AppMemMask), +            PtrShift), +        ShadowBase); +    Value *SrcShadowData = IRB.CreateIntToPtr(SrcShadowDataInt, IRB.getPtrTy()); + +    if (NeedsMemMove) { +      IRB.CreateMemMove(ShadowData, Align(1ull << PtrShift), SrcShadowData, +                        Align(1ull << PtrShift), IRB.CreateShl(Size, PtrShift)); +    } else { +      IRB.CreateMemCpy(ShadowData, Align(1ull << PtrShift), SrcShadowData, +                       Align(1ull << PtrShift), IRB.CreateShl(Size, PtrShift)); +    }    }    return true; @@ -890,6 +965,16 @@ PreservedAnalyses TypeSanitizerPass::run(Module &M,    for (Function &F : M) {      const TargetLibraryInfo &TLI = FAM.getResult<TargetLibraryAnalysis>(F);      TySan.sanitizeFunction(F, TLI); +    if (ClVerifyOutlinedInstrumentation && ClOutlineInstrumentation) { +      // Outlined instrumentation is a new option, and so this exists to +      // verify there is no difference in behaviour between the options. +      // If the outlined instrumentation triggers a verification failure +      // when the original inlined instrumentation does not, or vice versa, +      // then there is a discrepency which should be investigated. +      ClOutlineInstrumentation = false; +      TySan.sanitizeFunction(F, TLI); +      ClOutlineInstrumentation = true; +    }    }    return PreservedAnalyses::none(); | 
