Personal tools
You are here: Home Courses CS492D Automated SW Analysis, Fall 17 IntWrite.cpp

IntWrite.cpp

IntWrite.cpp — C++ source code, 5 kB (5565 bytes)

File contents

#define DEBUG_TYPE "IntWrite"

#include <iostream>

#include "llvm/DebugInfo.h"
#include "llvm/Pass.h"
#include "llvm/PassManager.h"

#include "llvm/ADT/Statistic.h"

#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/IRBuilder.h"

#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "../lib/IR/ConstantsContext.h"

using namespace llvm;
using namespace std;

namespace {
  struct IntWrite: public FunctionPass {
    static char ID; // Pass identification, replacement for typeid

		IntWrite() : FunctionPass(ID) {}

		Type *intTy, *ptrTy, *voidTy, *boolTy ; // These variables are to store the type instances for primitive types.
		
		Constant * p_init ; // points to the function instance of _init_.
		Constant * p_probe ; // points to the function instance of _probe_.

		virtual bool doInitialization(Module &M) {
			/* doInitialization() is executed once per target module,
			 * and executed before any invocation of runOnFunction().
			 * This function is for initialization and the module level 
			 * instrumentation (e.g., add functions). */

			/* check if there is a function in a target program that conflicts
			 * with the probe functions */			
			if (M.getFunction(StringRef("_init_")) != NULL) {
				errs() << "Error: function _init_() already exists.\n" ;
				exit(1) ;
			}
			if (M.getFunction(StringRef("_probe_")) != NULL) {
				errs() << "Error: function _probe_() already exists.\n" ;
				exit(1) ;
			}

			/* store the type instances for primitive types */
			intTy = Type::getInt32Ty(M.getContext()) ;
			ptrTy = Type::getInt8PtrTy(M.getContext()) ;
			voidTy = Type::getVoidTy(M.getContext()) ;
			boolTy = Type::getInt1Ty(M.getContext()) ;
			voidTy = Type::getVoidTy(M.getContext()) ;

			/* add a new declaration of function _init_ which has no argument */
			FunctionType * fty = FunctionType::get(voidTy, false) ;
			p_init = M.getOrInsertFunction("_init_", fty) ;

			/* add a new declaration of function _probe_ which accept three
			 * arguments (i.e., int, char *, and int) */
			Type * args_types[3] ;
			args_types[0] = intTy ; //Type::getInt32Ty(*ctx) ;
			args_types[1] = ptrTy ; //Type::getInt8PtrTy(*ctx) ;	
			args_types[2] = intTy ; //Type::getInt32Ty(*ctx) ;	
			p_probe = M.getOrInsertFunction("_probe_", 
					FunctionType::get(voidTy, ArrayRef<Type *>(args_types), false)) ;

			/* add a function call to _init_ at the beginning of 
			 * the main function*/
			Function * mainFunc = M.getFunction(StringRef("main")) ;
			if (mainFunc != NULL) {
				IRBuilder<> builder(M.getFunction(StringRef("main"))->getEntryBlock().getFirstInsertionPt()) ;
				builder.CreateCall(p_init, Twine("")) ;
			}

			return true ;
		} // doInitialization.

		virtual bool doFinalization(Module &M) {
			/* This function is executed once per target module after
			 * all executions of runOnFunction() under the module. */

			return false ;
		} //doFinalization.

    virtual bool runOnFunction(Function &F) {
			/* This function is invoked once for every function in the target 
			 * module by LLVM */

			/* Invoke runOnBasicBlock() for each basic block under F. */
			for (Function::iterator itr = F.begin() ; itr != F.end() ; itr++) {
				runOnBasicBlock(*itr) ;
			}

      return true;
    } //runOnFunction.

		bool runOnBasicBlock (BasicBlock &B) {
			/* This function is invoked by runOnFunction() for each basic block
			 * in the function. Note that this is not invoked by LLVM and different
			 * from runOnBasicBlock() of BasicBlockPass.*/

			for (BasicBlock::iterator i = B.begin() ; i != B.end() ; i++) {
				/* for each instruction of the basic block in order */

				if (i->getOpcode() == Instruction::Store) {
					if (i->getOperand(0)->getType() == intTy) {
						StoreInst * st = dyn_cast<StoreInst>(i) ;

						/* add a function call to _probe_ right before
						 * a store instruction on an integer variable. */

						int loc = st->getDebugLoc().getLine() ; // the location of the current instruction.
						Value * var = st->getPointerOperand() ; // the target variable 
						Value * val = st->getOperand(0) ; // the value to be assigned.

						IRBuilder<> builder(i) ;
						Value * args[3] ;
						args[0] = ConstantInt::get(intTy, loc, false) ; // location of store instruction.
						args[1] = builder.CreateGlobalStringPtr(var->getName(), "") ; // create a new string constant of the variable name, and get the pointer to it.
						args[2] = val ; // the value to be assigned to the variable.
						builder.CreateCall(p_probe, args, Twine("")) ;
						continue ;
					}
				}	
			}
			return true ;
		} // runOnBasicBlock.
  };
}

/* The code in the remaining part is to register this Pass to
 * LLVM Pass Manager such that LLVM/Clang can use it. */
char IntWrite::ID = 0;

namespace llvm {
	void initializeIntWritePass(llvm::PassRegistry &) ;
}

INITIALIZE_PASS_BEGIN(IntWrite, "IntWrite", "monitor writes to integers", false, false)
INITIALIZE_PASS_END(IntWrite, "IntWrite", "monitor writes to integers", false,  false) 

static struct Register {
	Register() {
		initializeIntWritePass(*llvm::PassRegistry::getPassRegistry()) ;
	}
} X;

static void registerIntWritePass(
	const llvm::PassManagerBuilder &Builder, 
	llvm::PassManagerBase &PM) {
	PM.add(new IntWrite) ;
}

static llvm::RegisterStandardPasses 
RegisterIntWrite(llvm::PassManagerBuilder::EP_EarlyAsPossible, registerIntWritePass) ;
Document Actions