----------------------------------------------------------------------------- DynamicCallCounter implementation -----------------------------------------------------------------------------
| 74 | // DynamicCallCounter implementation |
| 75 | //----------------------------------------------------------------------------- |
| 76 | bool DynamicCallCounter::runOnModule(Module &M) { |
| 77 | bool Instrumented = false; |
| 78 | |
| 79 | // Function name <--> IR variable that holds the call counter |
| 80 | llvm::StringMap<Constant *> CallCounterMap; |
| 81 | // Function name <--> IR variable that holds the function name |
| 82 | llvm::StringMap<Constant *> FuncNameMap; |
| 83 | |
| 84 | auto &CTX = M.getContext(); |
| 85 | |
| 86 | // STEP 1: For each function in the module, inject a call-counting code |
| 87 | // -------------------------------------------------------------------- |
| 88 | for (auto &F : M) { |
| 89 | if (F.isDeclaration()) |
| 90 | continue; |
| 91 | |
| 92 | // Get an IR builder. Sets the insertion point to the top of the function |
| 93 | IRBuilder<> Builder(&*F.getEntryBlock().getFirstInsertionPt()); |
| 94 | |
| 95 | // Create a global variable to count the calls to this function |
| 96 | std::string CounterName = "CounterFor_" + std::string(F.getName()); |
| 97 | Constant *Var = CreateGlobalCounter(M, CounterName); |
| 98 | CallCounterMap[F.getName()] = Var; |
| 99 | |
| 100 | // Create a global variable to hold the name of this function |
| 101 | auto FuncName = Builder.CreateGlobalString(F.getName()); |
| 102 | FuncNameMap[F.getName()] = FuncName; |
| 103 | |
| 104 | // Inject instruction to increment the call count each time this function |
| 105 | // executes |
| 106 | LoadInst *Load2 = Builder.CreateLoad(IntegerType::getInt32Ty(CTX), Var); |
| 107 | Value *Inc2 = Builder.CreateAdd(Builder.getInt32(1), Load2); |
| 108 | Builder.CreateStore(Inc2, Var); |
| 109 | |
| 110 | // The following is visible only if you pass -debug on the command line |
| 111 | // *and* you have an assert build. |
| 112 | LLVM_DEBUG(dbgs() << " Instrumented: " << F.getName() << "\n"); |
| 113 | |
| 114 | Instrumented = true; |
| 115 | } |
| 116 | |
| 117 | // Stop here if there are no function definitions in this module |
| 118 | if (false == Instrumented) |
| 119 | return Instrumented; |
| 120 | |
| 121 | // STEP 2: Inject the declaration of printf |
| 122 | // ---------------------------------------- |
| 123 | // Create (or _get_ in cases where it's already available) the following |
| 124 | // declaration in the IR module: |
| 125 | // declare i32 @printf(i8*, ...) |
| 126 | // It corresponds to the following C declaration: |
| 127 | // int printf(char *, ...) |
| 128 | PointerType *PrintfArgTy = PointerType::getUnqual(Type::getInt8Ty(CTX)); |
| 129 | FunctionType *PrintfTy = |
| 130 | FunctionType::get(IntegerType::getInt32Ty(CTX), PrintfArgTy, |
| 131 | /*IsVarArgs=*/true); |
| 132 | |
| 133 | FunctionCallee Printf = M.getOrInsertFunction("printf", PrintfTy); |
nothing calls this directly
no test coverage detected