bool TypeChecksOpt::runOnModule(Module &M) { TS = &getAnalysis<dsa::TypeSafety<TDDataStructures> >(); // Create the necessary prototypes VoidTy = IntegerType::getVoidTy(M.getContext()); Int8Ty = IntegerType::getInt8Ty(M.getContext()); Int32Ty = IntegerType::getInt32Ty(M.getContext()); Int64Ty = IntegerType::getInt64Ty(M.getContext()); VoidPtrTy = PointerType::getUnqual(Int8Ty); TypeTagTy = Int8Ty; TypeTagPtrTy = PointerType::getUnqual(TypeTagTy); Constant *memsetF = M.getOrInsertFunction ("llvm.memset.i64", VoidTy, VoidPtrTy, Int8Ty, Int64Ty, Int32Ty, NULL); trackGlobal = M.getOrInsertFunction("trackGlobal", VoidTy, VoidPtrTy,/*ptr*/ TypeTagTy,/*type*/ Int64Ty,/*size*/ Int32Ty,/*tag*/ NULL); trackInitInst = M.getOrInsertFunction("trackInitInst", VoidTy, VoidPtrTy,/*ptr*/ Int64Ty,/*size*/ Int32Ty,/*tag*/ NULL); trackUnInitInst = M.getOrInsertFunction("trackUnInitInst", VoidTy, VoidPtrTy,/*ptr*/ Int64Ty,/*size*/ Int32Ty,/*tag*/ NULL); trackStoreInst = M.getOrInsertFunction("trackStoreInst", VoidTy, VoidPtrTy,/*ptr*/ TypeTagTy,/*type*/ Int64Ty,/*size*/ Int32Ty,/*tag*/ NULL); checkTypeInst = M.getOrInsertFunction("checkType", VoidTy, TypeTagTy,/*type*/ Int64Ty,/*size*/ TypeTagPtrTy, VoidPtrTy,/*ptr*/ Int32Ty,/*tag*/ NULL); copyTypeInfo = M.getOrInsertFunction("copyTypeInfo", VoidTy, VoidPtrTy,/*dest ptr*/ VoidPtrTy,/*src ptr*/ Int64Ty,/*size*/ Int32Ty,/*tag*/ NULL); setTypeInfo = M.getOrInsertFunction("setTypeInfo", VoidTy, VoidPtrTy,/*dest ptr*/ TypeTagPtrTy,/*metadata*/ Int64Ty,/*size*/ TypeTagTy, VoidPtrTy, Int32Ty,/*tag*/ NULL); trackStringInput = M.getOrInsertFunction("trackStringInput", VoidTy, VoidPtrTy, Int32Ty, NULL); getTypeTag = M.getOrInsertFunction("getTypeTag", VoidTy, VoidPtrTy, /*ptr*/ Int64Ty, /*size*/ TypeTagPtrTy, /*dest for type tag*/ Int32Ty, /*tag*/ NULL); MallocFunc = M.getFunction("malloc"); for(Value::use_iterator User = trackGlobal->use_begin(); User != trackGlobal->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { std::vector<Value*>Args; Args.push_back(CI->getOperand(1)); Args.push_back(CI->getOperand(3)); Args.push_back(CI->getOperand(4)); CallInst::Create(trackInitInst, Args, "", CI); toDelete.push_back(CI); } } for(Value::use_iterator User = checkTypeInst->use_begin(); User != checkTypeInst->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(4)->stripPointerCasts(), CI->getParent()->getParent())) { toDelete.push_back(CI); } } for(Value::use_iterator User = trackStoreInst->use_begin(); User != trackStoreInst->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { toDelete.push_back(CI); } } // for alloca's if they are type known // assume initialized with TOP for(Value::use_iterator User = trackUnInitInst->use_begin(); User != trackUnInitInst->use_end(); ) { CallInst *CI = dyn_cast<CallInst>(*(User++)); assert(CI); // check if operand is an alloca inst. if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { CI->setCalledFunction(trackInitInst); if(AllocaInst *AI = dyn_cast<AllocaInst>(CI->getOperand(1)->stripPointerCasts())) { // Initialize the allocation to NULL std::vector<Value *> Args2; Args2.push_back(CI->getOperand(1)); Args2.push_back(ConstantInt::get(Int8Ty, 0)); Args2.push_back(CI->getOperand(2)); Args2.push_back(ConstantInt::get(Int32Ty, AI->getAlignment())); CallInst::Create(memsetF, Args2, "", CI); } } } if(MallocFunc) { for(Value::use_iterator User = MallocFunc->use_begin(); User != MallocFunc->use_end(); User ++) { CallInst *CI = dyn_cast<CallInst>(*User); if(!CI) continue; if(TS->isTypeSafe(CI, CI->getParent()->getParent())){ CastInst *BCI = BitCastInst::CreatePointerCast(CI, VoidPtrTy); CastInst *Size = CastInst::CreateSExtOrBitCast(CI->getOperand(1), Int64Ty); Size->insertAfter(CI); BCI->insertAfter(Size); std::vector<Value *>Args; Args.push_back(BCI); Args.push_back(Size); Args.push_back(ConstantInt::get(Int32Ty, 0)); CallInst *CINew = CallInst::Create(trackInitInst, Args); CINew->insertAfter(BCI); } } } // also do for mallocs/calloc/other allocators??? // other allocators?? for(Value::use_iterator User = copyTypeInfo->use_begin(); User != copyTypeInfo->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { std::vector<Value*> Args; Args.push_back(CI->getOperand(1)); Args.push_back(CI->getOperand(3)); // size Args.push_back(CI->getOperand(4)); CallInst::Create(trackInitInst, Args, "", CI); toDelete.push_back(CI); } } for(Value::use_iterator User = setTypeInfo->use_begin(); User != setTypeInfo->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { std::vector<Value*> Args; Args.push_back(CI->getOperand(1)); Args.push_back(CI->getOperand(3)); // size Args.push_back(CI->getOperand(6)); CallInst::Create(trackInitInst, Args, "", CI); toDelete.push_back(CI); } } for(Value::use_iterator User = getTypeTag->use_begin(); User != getTypeTag->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { AllocaInst *AI = dyn_cast<AllocaInst>(CI->getOperand(3)->stripPointerCasts()); assert(AI); std::vector<Value*>Args; Args.push_back(CI->getOperand(3)); Args.push_back(ConstantInt::get(Int8Ty, 255)); Args.push_back(CI->getOperand(2)); Args.push_back(ConstantInt::get(Int32Ty, AI->getAlignment())); CallInst::Create(memsetF, Args, "", CI); toDelete.push_back(CI); } } numSafe += toDelete.size(); while(!toDelete.empty()) { Instruction *I = toDelete.back(); toDelete.pop_back(); I->eraseFromParent(); } return (numSafe > 0); }
/** * Inserts an argument. * @param rw_newInstr rewrite rule - new instruction * @param I instruction * @param CalleeF function to be called * @param variables map of found parameters from config * @param where position of the placement of the new instruction * @return a vector of arguments for the call that is to be inserted * and a pointer to the instruction after/before the new call * is going to be inserted (it is either I or some newly added * argument) */ tuple<vector<Value *>, Instruction*> InsertArgument(InstrumentInstruction rw_newInstr, Instruction *I, Function* CalleeF, const map <string, Value*>& variables, InstrumentPlacement where) { std::vector<Value *> args; unsigned i = 0; Instruction* nI = I; for (const string& arg : rw_newInstr.parameters) { if (i == rw_newInstr.parameters.size() - 1) { break; } auto var = variables.find(arg); if (var == variables.end()) { // NOTE: in future think also about other types than ConstantInt int argInt; try { argInt = stoi(arg); LLVMContext &Context = getGlobalContext(); Value *intValue = ConstantInt::get(Type::getInt32Ty(Context), argInt); args.push_back(intValue); } catch (invalid_argument) { logger.write_error("Problem with instruction arguments: invalid argument."); } catch (out_of_range) { logger.write_error("Problem with instruction arguments: out of range."); } } else { unsigned argIndex = 0; for (Function::ArgumentListType::iterator sit=CalleeF->getArgumentList().begin(); sit != CalleeF->getArgumentList().end(); ++sit) { Value *argV = &*sit; if (i == argIndex) { if (argV->getType() != var->second->getType()) { //TODO other types? if (!var->second->getType()->isPtrOrPtrVectorTy() && !var->second->getType()->isIntegerTy()) { args.push_back(var->second); } else { CastInst *CastI; if (var->second->getType()->isPtrOrPtrVectorTy()) { CastI = CastInst::CreatePointerCast(var->second, argV->getType()); } else { CastI = CastInst::CreateIntegerCast(var->second, argV->getType(), true); //TODO do something about signed argument } if (Instruction *Inst = dyn_cast<Instruction>(var->second)) CloneMetadata(Inst, CastI); if (where == InstrumentPlacement::BEFORE) { // we want to insert before I, that is: // %c = cast ... // newInstr // I // // NOTE that we do not set nI in this case, // so that the new instruction that we will insert // is inserted before I (and after all arguments // we added here) CastI->insertBefore(I); } else { // we want to insert after I, that is: // I // %c = cast ... // newInstr // // --> we must update the nI, so that the new // instruction is inserted after the arguments CastI->insertAfter(I); nI = CastI; } args.push_back(CastI); } } else{ args.push_back(var->second); } break; } argIndex++; } } i++; } return make_tuple(args,nI); }
bool partition::runOnLoop(Loop* L, LPPassManager &LPM) { errs() << "*************************** Loop encountered: ************************" << '\n' << L->getHeader()->getName() << '\n'; if (function->getName() != "main") return false; IntegerType* int32Ty = Type::getInt32Ty(*context); IntegerType* int64Ty = Type::getInt64Ty(*context); PointerType* voidPtrTy = Type::getInt8PtrTy(*context); FunctionType* funcTy = FunctionType::get(int32Ty, false); Constant* func1_c; Function* func1; func1_c = module->getOrInsertFunction("func1", funcTy); func1 = cast<Function>(func1_c); Function* pro = module->getFunction("produce"); Function* con = module->getFunction("consume"); BasicBlock* func1EntryBlock = BasicBlock::Create(*context, "entry.func1", func1); AllocaInst* i_var = new AllocaInst(int32Ty, NULL, 4, "i", func1EntryBlock); Value* liveIn; BasicBlock *forCond, *forBody, *forInc; ValueToValueMapTy VMap; std::map<BasicBlock *, BasicBlock *> BlockMap; for (Loop::block_iterator BB = L->block_begin(), BBe = L->block_end(); BB != BBe; ++BB) { BasicBlock* func1Block = CloneBasicBlock(*BB, VMap, ".func1", func1); BlockMap[*BB] = func1Block; if ((*BB)->getName() == "for.cond") forCond = func1Block; if ((*BB)->getName() == "for.body") forBody = func1Block; if ((*BB)->getName() == "for.inc") forInc = func1Block; for (BasicBlock::iterator it = func1Block->begin(), ite = func1Block->end(); it != ite; ++it) { for (User::op_iterator oit = it->op_begin(), oite = it->op_end(); oit != oite; ++oit) { if (VMap[*oit] != NULL) { *oit = VMap[*oit]; } else { Constant* cons = dyn_cast<Constant>(*oit); BranchInst* br = dyn_cast<BranchInst>(it); if (cons == NULL && br == NULL) { liveIn = *oit; *oit = i_var; } } } } if ((*BB)->getName() == "for.body") { Instruction* term = (*BB)->getTerminator(); term->removeFromParent(); for (int i = 0; i < 7; i++) { (*BB)->back().eraseFromParent(); } term->insertAfter(&(*BB)->back()); (*BB)->front().eraseFromParent(); LoadInst* load = new LoadInst(liveIn, "", false, 4, term); std::vector<Value *> produce_args; CastInst* cast = CastInst::CreateIntegerCast(load, int64Ty, true); cast->insertAfter(load); produce_args.push_back(cast); ConstantInt* val = ConstantInt::get(int32Ty, (uint32_t) 3); produce_args.push_back(val); CallInst::Create(pro, ArrayRef<Value*>(produce_args), "", term); produce_args.pop_back(); val = ConstantInt::get(int32Ty, (uint32_t) 2); produce_args.push_back(val); CallInst::Create(pro, ArrayRef<Value*>(produce_args), "", term); } } // set branch instructions to restructure the CFG in created function BasicBlock* func1EndBlock = BasicBlock::Create(*context, "if.end.func1", func1); BasicBlock* garbageBB = BasicBlock::Create(*context, "garbage", func1); ConstantInt* retVal_g = ConstantInt::get(int32Ty, (uint32_t) 0); ReturnInst* ret_g = ReturnInst::Create(*context, retVal_g, garbageBB); for (Function::iterator fit = func1->begin(), fite = func1->end(); fit != fite; ++fit) { if (fit->getTerminator() == NULL || fit->getName() == "garbage") continue; BranchInst* br = dyn_cast<BranchInst>(fit->getTerminator()); int numSuccessors = br->getNumSuccessors(); for (int i = 0; i < numSuccessors; i++) { BasicBlock* successor = br->getSuccessor(i); if (BlockMap[successor] != NULL) { br->setSuccessor(i, BlockMap[successor]); } else { br->setSuccessor(i, func1EndBlock); } } /* if (fit->getName() == "for.body.func1") { for (int i = 0; i < 4; i++) { BasicBlock::iterator it = fit->begin(); it->moveBefore(ret_g); } } */ } garbageBB->eraseFromParent(); BranchInst* br = dyn_cast<BranchInst>(forBody->getTerminator()); br->setSuccessor(0, forCond); forInc->eraseFromParent(); // Create return instruction for func1EndBlock and set a branch from loop header to func1EndBlock ConstantInt* retVal = ConstantInt::get(int32Ty, (uint32_t) 0); ReturnInst* ret1 = ReturnInst::Create(*context, retVal, func1EndBlock); BasicBlock* loopHeader = BlockMap.at(L->getHeader()); BranchInst* brInst = BranchInst::Create(loopHeader, func1EntryBlock); // add produce function call std::vector<Value *> produce_args; ConstantInt* val = ConstantInt::get(int64Ty, (uint64_t) 0); produce_args.push_back(val); val = ConstantInt::get(int32Ty, (uint32_t) 5); produce_args.push_back(val); CallInst::Create(pro, ArrayRef<Value*>(produce_args), "", func1EndBlock->getTerminator()); // add consume function call int q_id = 2; for (Value::use_iterator uit = i_var->use_begin(), uite = i_var->use_end(); uit != uite; ++uit) { std::vector<Value *> consume_args; ConstantInt* val = ConstantInt::get(int32Ty, (uint32_t) q_id); consume_args.push_back(val); CallInst* call = CallInst::Create(con, ArrayRef<Value*>(consume_args)); Instruction* inst = dyn_cast<Instruction>(*uit); call->insertAfter(inst); CastInst* cast = CastInst::CreateIntegerCast(call, int32Ty, true); cast->insertAfter(call); (*uit)->replaceAllUsesWith(cast); inst->eraseFromParent(); q_id++; } i_var->eraseFromParent(); // add produce and consume function calls to main thread // transmit the function pointer to created function by a produce call BasicBlock* loopPreheader = L->getLoopPreheader(); produce_args.clear(); CastInst* cast = CastInst::CreatePointerCast(func1, int64Ty); cast->insertBefore(loopPreheader->getTerminator()); produce_args.push_back(cast); val = ConstantInt::get(int32Ty, (uint32_t) 0); produce_args.push_back(val); CallInst::Create(pro, ArrayRef<Value*>(produce_args), "", loopPreheader->getTerminator()); // transmit induction variable to created function by a produce call Instruction* load = &L->getHeader()->front(); produce_args.clear(); cast = CastInst::CreateIntegerCast(load, int64Ty, true); cast->insertAfter(load); produce_args.push_back(cast); val = ConstantInt::get(int32Ty, (uint32_t) 4); produce_args.push_back(val); CallInst::Create(pro, ArrayRef<Value*>(produce_args))->insertAfter(cast); return true; }