LCOV - code coverage report
Current view: top level - core/src/instr - instr_llvm.cpp Hit Total Coverage
Test: ROOT-Sim master Documentation Coverage Lines: 1 5 20.0 %
Date: 2021-03-25 15:11:55

          Line data    Source code
       1           1 : /**
       2             :  * @file instr/instr_llvm.cpp
       3             :  *
       4             :  * @brief LLVM plugin to instrument memory writes
       5             :  * 
       6             :  * This is the LLVM plugin which instruments memory allocations so as to enable
       7             :  * transparent rollbacks of application code state.
       8             :  *
       9             :  * SPDX-FileCopyrightText: 2008-2021 HPDCS Group <rootsim@googlegroups.com>
      10             :  * SPDX-License-Identifier: GPL-3.0-only
      11             :  */
      12             : #include <instr/instr_llvm.hpp>
      13             : 
      14             : extern "C"
      15             : {
      16             :         #include <log/log.h>
      17             : }
      18             : 
      19             : #include "llvm/Analysis/TargetLibraryInfo.h"
      20             : #include "llvm/Config/llvm-config.h"
      21             : #include "llvm/IR/DerivedTypes.h"
      22             : #include "llvm/IR/GlobalValue.h"
      23             : #include "llvm/IR/InstIterator.h"
      24             : #include "llvm/IR/IntrinsicInst.h"
      25             : #include "llvm/IR/LegacyPassManager.h"
      26             : #include "llvm/Pass.h"
      27             : #include "llvm/Support/Casting.h"
      28             : #include "llvm/Transforms/IPO/PassManagerBuilder.h"
      29             : #include "llvm/Transforms/Utils/Cloning.h"
      30             : 
      31             : using namespace llvm;
      32             : 
      33             : namespace {
      34           0 :         enum instrumentation_stats {
      35             :                 TRACED_STORE,
      36             :                 TRACED_MEMSET,
      37             :                 TRACED_MEMCPY,
      38             :                 TRACED_CALL,
      39             :                 TRACED_ATOMIC,
      40             :                 TRACED_UNKNOWN,
      41             :                 INSTRUMENTATION_STATS_COUNT
      42             :         };
      43             : 
      44             :         static bool nullTermArrayContains(const char *const *arr,
      45             :                                           const char *val, size_t val_len)
      46             :         {
      47             :                 while (*arr) {
      48             :                         if (!strncmp(*arr, val, val_len) && !(*arr)[val_len])
      49             :                                 return true;
      50             :                         ++arr;
      51             :                 }
      52             :                 return false;
      53             :         }
      54             : 
      55             :         static bool isToSubstitute(StringRef s)
      56             :         {
      57             :                 return nullTermArrayContains(instr_cfg.to_substitute,
      58             :                                              s.data(), s.size());
      59             :         }
      60             : 
      61             :         static bool isToIgnore(StringRef s)
      62             :         {
      63             :                 return nullTermArrayContains(instr_cfg.to_ignore,
      64             :                                              s.data(), s.size());
      65             :         }
      66             : 
      67             :         static Function *CloneFunctionStub(Function &F, const char *suffix)
      68             :         {
      69             :                 std::string NewFName = F.getName().str() + suffix;
      70             :                 Function *NewF = Function::Create(
      71             :                         cast<FunctionType>(F.getValueType()),
      72             :                         F.getLinkage(),
      73             :                         F.getAddressSpace(),
      74             :                         NewFName,
      75             :                         F.getParent()
      76             :                 );
      77             :                 NewF->copyAttributesFrom(&F);
      78             :                 return NewF;
      79             :         }
      80             : 
      81             :         static void CloneFunctionIntoAndMap(Function *NewF, const Function &F,
      82             :                 ValueToValueMapTy &VMap, const char *suffix)
      83             :         {
      84             :                 Function::arg_iterator DestI = NewF->arg_begin();
      85             :                 for (const Argument &I : F.args()) {
      86             :                         DestI->setName(I.getName());
      87             :                         VMap[&I] = DestI++;
      88             :                 }
      89             : 
      90             :                 SmallVector<ReturnInst *, 8> Returns;
      91             :                 CloneFunctionInto(NewF, &F, VMap, true, Returns, suffix);
      92             : 
      93             :                 for (const Argument &I : F.args()) {
      94             :                         VMap.erase(&I);
      95             :                 }
      96             :                 // XXX: solves a LLVM bug but removes debug info from clones
      97             :                 NewF->setSubprogram(nullptr);
      98             :         }
      99             : 
     100             : class RootsimCC: public ModulePass {
     101             : public:
     102             :         RootsimCC() : ModulePass(ID){}
     103             : 
     104             :         virtual void getAnalysisUsage(AnalysisUsage &AU) const
     105             :         {
     106             :                 AU.addRequired<TargetLibraryInfoWrapperPass>();
     107             :         }
     108             : 
     109             :         bool runOnModule(Module &M)
     110             :         {
     111             : #if LOG_LEVEL <= LOG_DEBUG
     112             :                 errs() << "Instrumenting module " << raw_ostream::CYAN <<
     113             :                                 M.getName() << "\n";
     114             :                 errs().resetColor();
     115             : #endif
     116             : 
     117             :                 ValueToValueMapTy VMap;
     118             :                 std::vector<Function *> F_vec;
     119             :                 for (Function &F : M) {
     120             :                         if ((isSystemSide(F) && !isToSubstitute(F.getName()))
     121             :                                         || isToIgnore(F.getName())) {
     122             : #if LOG_LEVEL <= LOG_DEBUG
     123             :                                 errs() << "Ignoring function " << F.getName()
     124             :                                                 << "\n";
     125             : #endif
     126             :                         } else {
     127             : #if LOG_LEVEL <= LOG_DEBUG
     128             :                                 errs() << "Found function " << F.getName()
     129             :                                                 << "\n";
     130             : #endif
     131             :                                 F_vec.push_back(&F);
     132             :                         }
     133             :                 }
     134             : 
     135             :                 for (Function *F : F_vec) {
     136             :                         if (isToSubstitute(F->getName()))
     137             :                                 VMap[F] = CloneFunctionStub(*F, instr_cfg.sub_suffix);
     138             :                         else
     139             :                                 VMap[F] = CloneFunctionStub(*F, instr_cfg.proc_suffix);
     140             :                 }
     141             : 
     142             :                 for (Function *F : F_vec) {
     143             :                         if (F->isDeclaration() || isToSubstitute(F->getName()))
     144             :                                 continue;
     145             : 
     146             :                         Function *Cloned = cast<Function>(VMap[F]);
     147             :                         if (Cloned == nullptr)
     148             :                                 continue;
     149             : #if LOG_LEVEL <= LOG_DEBUG
     150             :                         errs() << "Processing " << Cloned->getName() << "\n";
     151             : #endif
     152             :                         CloneFunctionIntoAndMap(Cloned, *F, VMap,
     153             :                                                 instr_cfg.proc_suffix);
     154             : 
     155             :                         for (BasicBlock &B : *Cloned)
     156             :                                 for (Instruction &I : B)
     157             :                                         ;// TODO: incremental instrumentation
     158             :                 }
     159             : 
     160             :                 return true;
     161             :         }
     162             : 
     163             : private:
     164             :         static char ID;
     165             : 
     166             :         unsigned stats[INSTRUMENTATION_STATS_COUNT] = {0};
     167             : 
     168             :         bool isSystemSide(Function &F)
     169             :         {
     170             :                 enum llvm::LibFunc LLF;
     171             :                 return F.getIntrinsicID() || F.doesNotReturn() ||
     172             :                         getAnalysis<TargetLibraryInfoWrapperPass>()
     173             : #if LLVM_VERSION_MAJOR >= 10
     174             :                         .getTLI(F.getFunction()).getLibFunc(F.getFunction(), LLF);
     175             : #else
     176             :                         .getTLI().getLibFunc(F.getFunction(), LLF);
     177             : #endif
     178             :         }
     179             : 
     180             :         // TODO: this code has been refactored and improved but it is unused
     181             :         FunctionCallee InitMemtraceFunction(Module &M, const char *memtrace_name)
     182             :         {
     183             :                 Type *MemtraceArgs[] = {
     184             :                         PointerType::getUnqual(Type::getVoidTy(M.getContext())),
     185             :                         IntegerType::get(M.getContext(), sizeof(size_t) * CHAR_BIT)
     186             :                 };
     187             : 
     188             :                 FunctionType *Fty = FunctionType::get(
     189             :                         Type::getVoidTy(M.getContext()),
     190             :                         MemtraceArgs,
     191             :                         false
     192             :                 );
     193             : 
     194             :                 return M.getOrInsertFunction(memtrace_name, Fty);
     195             :         }
     196             : 
     197             :         // TODO: this code has been refactored and improved but it is unused
     198             :         void InstrumentWriteInstruction(Module &M, Instruction *TI,
     199             :                                         FunctionCallee memtrace_fnc)
     200             :         {
     201             :                 if (!TI->mayWriteToMemory()) {
     202             :                         return;
     203             :                 }
     204             : 
     205             :                 Value *args[2];
     206             : 
     207             :                 if (StoreInst *SI = dyn_cast<StoreInst>(TI)) {
     208             :                         Value *V = SI->getPointerOperand();
     209             :                         PointerType *pointerType = cast<PointerType>(V->getType());
     210             :                         uint64_t storeSize = M.getDataLayout()
     211             :                                 .getTypeStoreSize(pointerType->getPointerElementType());
     212             :                         args[0] = V;
     213             :                         args[1] = ConstantInt::get(IntegerType::get(M.getContext(),
     214             :                                 sizeof(size_t) * CHAR_BIT), storeSize);
     215             :                         ++stats[TRACED_STORE];
     216             :                 } else if (MemSetInst *MSI = dyn_cast<MemSetInst>(TI)) {
     217             :                         args[0] = MSI->getRawDest();
     218             :                         args[1] = MSI->getLength();
     219             :                         ++stats[TRACED_MEMSET];
     220             :                 } else if (MemCpyInst *MCI = dyn_cast<MemCpyInst>(TI)) {
     221             :                         args[0] = MCI->getRawDest();
     222             :                         args[1] = MCI->getLength();
     223             :                         ++stats[TRACED_STORE];
     224             :                 } else {
     225             :                          if (isa<CallBase>(TI)) {
     226             :                                  ++stats[TRACED_CALL];
     227             :                         } else if (TI->isAtomic()) {
     228             :                                 errs() << "Encountered an atomic non-store instruction in function "
     229             :                                         << TI->getParent()->getParent()->getName() << "\n";
     230             :                                 ++stats[TRACED_ATOMIC];
     231             :                         } else {
     232             :                                 errs() << "Encountered an unknown memory writing instruction in function "
     233             :                                         << TI->getParent()->getParent()->getName() << "\n";
     234             :                                 ++stats[TRACED_UNKNOWN];
     235             :                         }
     236             :                         return;
     237             :                 }
     238             : 
     239             :                 CallInst::Create(memtrace_fnc, args, "", TI);
     240             :         }
     241             : };
     242             : }
     243             : 
     244             : char RootsimCC::ID = 0;
     245             : 
     246           0 : static void loadPass(
     247             :         const PassManagerBuilder &Builder,
     248             :         llvm::legacy::PassManagerBase &PM
     249             : ) {
     250             :         (void)Builder;
     251             :         PM.add(new RootsimCC());
     252             : }
     253             : 
     254           0 : static RegisterStandardPasses clangtoolLoader_Ox(
     255             :         PassManagerBuilder::EP_ModuleOptimizerEarly,
     256             :         loadPass
     257             : );
     258           0 : static RegisterStandardPasses clangtoolLoader_O0(
     259             :         PassManagerBuilder::EP_EnabledOnOptLevel0,
     260             :         loadPass
     261             : );

Generated by: LCOV version 1.14