| #include "safecode/Config/config.h" |
| #include "SCUtils.h" |
| #include "InsertPoolChecks.h" |
| #include "llvm/Instruction.h" |
| #include "llvm/Module.h" |
| #include "llvm/Support/CommandLine.h" |
| #include "llvm/Support/InstIterator.h" |
| #include <iostream> |
| #include "llvm/ADT/VectorExtras.h" |
| #include "llvm/ADT/Statistic.h" |
| #include "llvm/Support/Debug.h" |
| |
| using namespace llvm; |
| |
| char llvm::InsertPoolChecks::ID = 0; |
| |
| extern Value *getRepresentativeMetaPD(Value *); |
| RegisterPass<InsertPoolChecks> ipc("safecode", "insert runtime checks"); |
| |
| // Options for Enabling/Disabling the Insertion of Various Checks |
| cl::opt<bool> EnableIncompleteChecks ("enable-incompletechecks", cl::Hidden, |
| cl::init(false), |
| cl::desc("Enable Checks on Incomplete Nodes")); |
| |
| cl::opt<bool> EnableNullChecks ("enable-nullchecks", cl::Hidden, |
| cl::init(false), |
| cl::desc("Enable Checks on NULL Pools")); |
| |
| |
| cl::opt<bool> DisableLSChecks ("disable-lschecks", cl::Hidden, |
| cl::init(false), |
| cl::desc("Disable Load/Store Checks")); |
| |
| cl::opt<bool> DisableGEPChecks ("disable-gepchecks", cl::Hidden, |
| cl::init(false), |
| cl::desc("Disable GetElementPtr(GEP) Checks")); |
| |
| cl::opt<bool> DisableIntrinsicChecks ("disable-intrinchecks", cl::Hidden, |
| cl::init(false), |
| cl::desc("Disable Intrinsic Checks")); |
| |
| // Options for where to insert various initialization code |
| cl::opt<string> InitFunctionName ("initfunc", |
| cl::desc("Specify name of initialization " |
| "function"), |
| cl::value_desc("function name")); |
| |
| // Pass Statistics |
| namespace { |
| STATISTIC (NullChecks , |
| "Poolchecks with NULL pool descriptor"); |
| STATISTIC (FullChecks , |
| "Poolchecks with non-NULL pool descriptor"); |
| STATISTIC (MissChecks , |
| "Poolchecks omitted due to bad pool descriptor"); |
| STATISTIC (PoolChecks , "Poolchecks Added"); |
| STATISTIC (BoundChecks, |
| "Bounds checks inserted"); |
| |
| STATISTIC (MissedIncompleteChecks , |
| "Poolchecks missed because of incompleteness"); |
| STATISTIC (MissedMultDimArrayChecks , |
| "Multi-dimensional array checks"); |
| |
| STATISTIC (MissedStackChecks , "Missed stack checks"); |
| STATISTIC (MissedGlobalChecks , "Missed global checks"); |
| STATISTIC (MissedNullChecks , "Missed PD checks"); |
| |
| // Object registration statistics |
| STATISTIC (StackRegisters, "Stack registrations"); |
| STATISTIC (SavedRegAllocs, "Stack registrations avoided"); |
| } |
| |
| namespace llvm { |
| bool InsertPoolChecks::runOnModule(Module &M) { |
| abcPass = getAnalysisToUpdate<ArrayBoundsCheck>(); |
| // budsPass = &getAnalysis<CompleteBUDataStructures>(); |
| #ifndef LLVA_KERNEL |
| paPass = getAnalysisToUpdate<PoolAllocateGroup>(); |
| #if 0 |
| if (!paPass) |
| paPass = getAnalysisToUpdate<PoolAllocateSimple>(); |
| #endif |
| assert (paPass && "Pool Allocation Transform *must* be run first!"); |
| efPass = &getAnalysis<EmbeCFreeRemoval>(); |
| TD = &getAnalysis<TargetData>(); |
| #else |
| TDPass = &getAnalysis<TDDataStructures>(); |
| #endif |
| |
| //add the new poolcheck prototype |
| addPoolCheckProto(M); |
| #ifndef LLVA_KERNEL |
| //register global arrays and collapsed nodes with global pools |
| registerGlobalArraysWithGlobalPools(M); |
| #endif |
| |
| // Replace old poolcheck with the new one |
| addPoolChecks(M); |
| |
| // Add stack registrations |
| registerStackObjects (M); |
| |
| // |
| // Update the statistics. |
| // |
| PoolChecks = NullChecks + FullChecks; |
| |
| return true; |
| } |
| |
| #ifndef LLVA_KERNEL |
| void |
| InsertPoolChecks::registerGlobalArraysWithGlobalPools(Module &M) { |
| |
| // |
| // Find the main() function. For FORTRAN programs converted to C using the |
| // NAG f2c tool, the function is named MAIN__. |
| // |
| Function *MainFunc = M.getFunction("main"); |
| if (MainFunc == 0 || MainFunc->isDeclaration()) { |
| MainFunc = M.getFunction("MAIN__"); |
| if (MainFunc == 0 || MainFunc->isDeclaration()) { |
| std::cerr << "Cannot do array bounds check for this program" |
| << "no 'main' function yet!\n"; |
| abort(); |
| } |
| } |
| |
| // First register, argc and argv |
| Function::arg_iterator AI = MainFunc->arg_begin(), AE = MainFunc->arg_end(); |
| if (AI != AE) { |
| //There is argc and argv |
| Value *Argc = AI; |
| AI++; |
| Value *Argv = AI; |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*MainFunc); |
| Value *PH= getPoolHandle(Argv, MainFunc, *FI); |
| Constant *PoolRegister = paPass->PoolRegister; |
| BasicBlock::iterator InsertPt = MainFunc->getEntryBlock().begin(); |
| |
| // Insert the registration after all calls to poolinit(). Also skip |
| // cast, alloca, and binary operators. |
| while ((isa<CallInst>(InsertPt)) || |
| isa<CastInst>(InsertPt) || |
| isa<AllocaInst>(InsertPt) || |
| isa<BinaryOperator>(InsertPt)) { |
| if (CallInst * CI = dyn_cast<CallInst>(InsertPt)) |
| if (Function * F = CI->getCalledFunction()) |
| if (F->getName() == "poolinit") |
| ++InsertPt; |
| else |
| break; |
| else |
| break; |
| else |
| ++InsertPt; |
| } |
| |
| if (PH) { |
| Type *VoidPtrType = PointerType::getUnqual(Type::Int8Ty); |
| Instruction *GVCasted = CastInst::createPointerCast(Argv, |
| VoidPtrType, Argv->getName()+"casted",InsertPt); |
| const Type* csiType = Type::Int32Ty; |
| Value *AllocSize = CastInst::createZExtOrBitCast(Argc, |
| csiType, Argc->getName()+"casted",InsertPt); |
| AllocSize = BinaryOperator::create(Instruction::Mul, AllocSize, |
| ConstantInt::get(csiType, 4), "sizetmp", InsertPt); |
| std::vector<Value *> args; |
| args.push_back (PH); |
| args.push_back (GVCasted); |
| args.push_back (AllocSize); |
| CallInst::Create(PoolRegister, args.begin(), args.end(), "", InsertPt); |
| } else { |
| std::cerr << "argv's pool descriptor is not present. \n"; |
| // abort(); |
| } |
| } |
| |
| // Now iterate over globals and register all the arrays |
| Type *VoidPtrType = PointerType::getUnqual(Type::Int8Ty); |
| Type *PoolDescType = ArrayType::get(VoidPtrType, 50); |
| Type *PoolDescPtrTy = PointerType::getUnqual(PoolDescType); |
| |
| Module::global_iterator GI = M.global_begin(), GE = M.global_end(); |
| for ( ; GI != GE; ++GI) { |
| if (GlobalVariable *GV = dyn_cast<GlobalVariable>(GI)) { |
| if (GV->getType() != PoolDescPtrTy) { |
| DSGraph &G = paPass->getGlobalsGraph(); |
| DSNode *DSN = G.getNodeForValue(GV).getNode(); |
| Value * AllocSize; |
| const Type* csiType = Type::Int32Ty; |
| const Type * GlobalType = GV->getType()->getElementType(); |
| AllocSize = ConstantInt::get (csiType, TD->getABITypeSize(GlobalType)); |
| Constant *PoolRegister = paPass->PoolRegister; |
| BasicBlock::iterator InsertPt = MainFunc->getEntryBlock().begin(); |
| //skip the calls to poolinit |
| while ((isa<CallInst>(InsertPt)) || |
| isa<CastInst>(InsertPt) || |
| isa<AllocaInst>(InsertPt) || |
| isa<BinaryOperator>(InsertPt)) { |
| if (CallInst * CI = dyn_cast<CallInst>(InsertPt)) |
| if (Function * F = CI->getCalledFunction()) |
| if (F->getName() == "poolinit") |
| ++InsertPt; |
| else |
| break; |
| else |
| break; |
| else |
| ++InsertPt; |
| } |
| |
| Value * PH = paPass->getGlobalPool (DSN); |
| if (PH) { |
| Instruction *GVCasted = CastInst::createPointerCast(GV, |
| VoidPtrType, GV->getName()+"casted",InsertPt); |
| std::vector<Value *> args; |
| args.push_back (PH); |
| args.push_back (GVCasted); |
| args.push_back (AllocSize); |
| CallInst::Create(PoolRegister, args.begin(), args.end(), "", InsertPt); |
| } else { |
| std::cerr << "pool descriptor not present for " << *GV << std::endl; |
| #if 0 |
| abort(); |
| #endif |
| } |
| } |
| } |
| } |
| } |
| #endif |
| |
| void |
| InsertPoolChecks::registerStackObjects (Module &M) { |
| for (Module::iterator FI = M.begin(); FI != M.end(); ++FI) |
| for (Function::iterator BI = FI->begin(); BI != FI->end(); ++BI) |
| for (BasicBlock::iterator I = BI->begin(); I != BI->end(); ++I) |
| if (AllocaInst * AI = dyn_cast<AllocaInst>(I)) { |
| registerAllocaInst (AI, AI); |
| } |
| } |
| |
| void |
| InsertPoolChecks::registerAllocaInst(AllocaInst *AI, AllocaInst *AIOrig) { |
| // |
| // Get the function information for this function. |
| // |
| Function *F = AI->getParent()->getParent(); |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F); |
| Value *temp = FI->MapValueToOriginal(AI); |
| if (temp) |
| AIOrig = dyn_cast<AllocaInst>(temp); |
| |
| // |
| // Get the pool handle for the node that this contributes to... |
| // |
| Function *FOrig = AIOrig->getParent()->getParent(); |
| DSNode *Node = getDSNode(AIOrig, FOrig); |
| if (!Node) return; |
| assert ((Node->isAllocaNode()) && "DSNode for alloca is missing stack flag!"); |
| |
| // |
| // Only register the stack allocation if it may be the subject of a run-time |
| // check. This can only occur when the object is used like an array because: |
| // 1) GEP checks are only done when accessing arrays. |
| // 2) Load/Store checks are only done on collapsed nodes (which appear to be |
| // used like arrays). |
| // |
| #if 0 |
| if (!(Node->isArray())) |
| return; |
| #endif |
| |
| // |
| // Determine if any use (direct or indirect) escapes this function. If not, |
| // then none of the checks will consult the MetaPool, and we can forego |
| // registering the alloca. |
| // |
| bool MustRegisterAlloca = false; |
| std::vector<Value *> AllocaWorkList; |
| AllocaWorkList.push_back (AI); |
| while ((!MustRegisterAlloca) && (AllocaWorkList.size())) { |
| Value * V = AllocaWorkList.back(); |
| AllocaWorkList.pop_back(); |
| Value::use_iterator UI = V->use_begin(); |
| for (; UI != V->use_end(); ++UI) { |
| // We cannot handle PHI nodes or Select instructions |
| if (isa<PHINode>(UI) || isa<SelectInst>(UI)) { |
| MustRegisterAlloca = true; |
| continue; |
| } |
| |
| // The pointer escapes if it's stored to memory somewhere. |
| StoreInst * SI; |
| if ((SI = dyn_cast<StoreInst>(UI)) && (SI->getOperand(0) == V)) { |
| MustRegisterAlloca = true; |
| continue; |
| } |
| |
| // GEP instructions are okay, but need to be added to the worklist |
| if (isa<GetElementPtrInst>(UI)) { |
| AllocaWorkList.push_back (*UI); |
| continue; |
| } |
| |
| // Cast instructions are okay as long as they cast to another pointer |
| // type |
| if (CastInst * CI = dyn_cast<CastInst>(UI)) { |
| if (isa<PointerType>(CI->getType())) { |
| AllocaWorkList.push_back (*UI); |
| continue; |
| } else { |
| MustRegisterAlloca = true; |
| continue; |
| } |
| } |
| |
| #if 0 |
| if (ConstantExpr *cExpr = dyn_cast<ConstantExpr>(UI)) { |
| if (cExpr->getOpcode() == Instruction::Cast) { |
| AllocaWorkList.push_back (*UI); |
| continue; |
| } else { |
| MustRegisterAlloca = true; |
| continue; |
| } |
| } |
| #endif |
| |
| CallInst * CI1; |
| if (CI1 = dyn_cast<CallInst>(UI)) { |
| if (!(CI1->getCalledFunction())) { |
| MustRegisterAlloca = true; |
| continue; |
| } |
| |
| std::string FuncName = CI1->getCalledFunction()->getName(); |
| if (FuncName == "exactcheck3") { |
| AllocaWorkList.push_back (*UI); |
| continue; |
| } else if ((FuncName == "llvm.memcpy.i32") || |
| (FuncName == "llvm.memcpy.i64") || |
| (FuncName == "llvm.memset.i32") || |
| (FuncName == "llvm.memset.i64") || |
| (FuncName == "llvm.memmove.i32") || |
| (FuncName == "llvm.memmove.i64") || |
| (FuncName == "llva_memcpy") || |
| (FuncName == "llva_memset") || |
| (FuncName == "llva_strncpy") || |
| (FuncName == "llva_invokememcpy") || |
| (FuncName == "llva_invokestrncpy") || |
| (FuncName == "llva_invokememset") || |
| (FuncName == "memcmp")) { |
| continue; |
| } else { |
| MustRegisterAlloca = true; |
| continue; |
| } |
| } |
| } |
| } |
| |
| if (!MustRegisterAlloca) { |
| ++SavedRegAllocs; |
| return; |
| } |
| |
| // |
| // Insert the alloca registration. |
| // |
| Value *PH = getPoolHandle(AIOrig, FOrig, *FI); |
| if (PH == 0 || isa<ConstantPointerNull>(PH)) return; |
| |
| Value *AllocSize = |
| ConstantInt::get(Type::Int32Ty, TD->getABITypeSize(AI->getAllocatedType())); |
| |
| if (AI->isArrayAllocation()) |
| AllocSize = BinaryOperator::create(Instruction::Mul, AllocSize, |
| AI->getOperand(0), "sizetmp", AI); |
| |
| // Insert object registration at the end of allocas. |
| Instruction *iptI = AI; |
| ++iptI; |
| if (AI->getParent() == (&(AI->getParent()->getParent()->getEntryBlock()))) { |
| BasicBlock::iterator InsertPt = AI->getParent()->begin(); |
| while (&(*(InsertPt)) != AI) |
| ++InsertPt; |
| while (isa<AllocaInst>(InsertPt)) |
| ++InsertPt; |
| iptI = InsertPt; |
| } |
| |
| // |
| // Insert a call to register the object. |
| // |
| Instruction *Casted = castTo (AI, PointerType::getUnqual(Type::Int8Ty), |
| AI->getName()+".casted", iptI); |
| Value * CastedPH = PH; |
| std::vector<Value *> args; |
| args.push_back (CastedPH); |
| args.push_back (Casted); |
| args.push_back (AllocSize); |
| Constant *PoolRegister = paPass->PoolRegister; |
| CallInst::Create (PoolRegister, args.begin(), args.end(), "", iptI); |
| |
| // |
| // Insert a call to unregister the object whenever the function can exit. |
| // |
| #if 1 |
| CastedPH = castTo (PH, |
| PointerType::getUnqual(Type::Int8Ty), |
| "allocph",Casted); |
| args.clear(); |
| args.push_back (CastedPH); |
| args.push_back (Casted); |
| for (Function::iterator BB = AI->getParent()->getParent()->begin(); |
| BB != AI->getParent()->getParent()->end(); |
| ++BB) { |
| iptI = BB->getTerminator(); |
| if (isa<ReturnInst>(iptI) || isa<UnwindInst>(iptI)) |
| CallInst::Create (StackFree, args.begin(), args.end(), "", iptI); |
| } |
| #endif |
| |
| // Update statistics |
| ++StackRegisters; |
| } |
| |
| void InsertPoolChecks::addPoolChecks(Module &M) { |
| if (!DisableGEPChecks) { |
| Module::iterator mI = M.begin(), mE = M.end(); |
| for ( ; mI != mE; ++mI) { |
| Function * F = mI; |
| Function::iterator fI = F->begin(), fE = F->end(); |
| for ( ; fI != fE; ++fI) { |
| BasicBlock * BB = fI; |
| addGetElementPtrChecks (BB); |
| } |
| } |
| } |
| if (!DisableLSChecks) addLoadStoreChecks(M); |
| } |
| |
| void |
| InsertPoolChecks::addGetActualValue (ICmpInst *SCI, unsigned operand) { |
| #if 1 |
| // We know that the operand is a pointer type |
| Value *op = SCI->getOperand(operand); |
| Function *F = SCI->getParent()->getParent(); |
| |
| #ifndef LLVA_KERNEL |
| #if 0 |
| // Some times the ECGraphs doesnt contain F for newly created cloned |
| // functions |
| if (!equivPass->ContainsDSGraphFor(*F)) { |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F); |
| op = FI->MapValueToOriginal(op); |
| if (!op) return; //abort(); |
| } |
| #endif |
| #endif |
| |
| Function *Fnew = F; |
| Value *PH = 0; |
| if (Argument *arg = dyn_cast<Argument>(op)) { |
| Fnew = arg->getParent(); |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*Fnew); |
| PH = getPoolHandle(op, Fnew, *FI); |
| } else if (Instruction *Inst = dyn_cast<Instruction>(op)) { |
| Fnew = Inst->getParent()->getParent(); |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*Fnew); |
| PH = getPoolHandle(op, Fnew, *FI); |
| } else if (isa<Constant>(op)) { |
| return; |
| // abort(); |
| } else if (!isa<ConstantPointerNull>(op)) { |
| //has to be a global |
| abort(); |
| } |
| op = SCI->getOperand(operand); |
| if (!isa<ConstantPointerNull>(op)) { |
| if (PH) { |
| if (1) { //HACK fixed |
| const Type * VoidPtrType = PointerType::getUnqual(Type::Int8Ty); |
| Value * PHVptr = castTo (PH, VoidPtrType, PH->getName()+".casted", SCI); |
| Value * OpVptr = castTo (op, VoidPtrType, op->getName()+".casted", SCI); |
| |
| std::vector<Value *> args = make_vector(PHVptr, OpVptr,0); |
| CallInst *CI = CallInst::Create (GetActualValue, args.begin(), args.end(), "getval", SCI); |
| Instruction *CastBack = castTo (CI, op->getType(), |
| op->getName()+".castback", SCI); |
| SCI->setOperand (operand, CastBack); |
| } |
| } else { |
| //It shouldn't work if PH is not null |
| } |
| } |
| #endif |
| } |
| |
| |
| #ifdef LLVA_KERNEL |
| // |
| // Method: addLSChecks() |
| // |
| // Description: |
| // Insert a poolcheck() into the code for a load or store instruction. |
| // |
| void InsertPoolChecks::addLSChecks(Value *V, Instruction *I, Function *F) { |
| DSGraph & TDG = TDPass->getDSGraph(*F); |
| DSNode * Node = TDG.getNodeForValue(V).getNode(); |
| |
| if (Node && Node->isNodeCompletelyFolded()) { |
| if (!EnableIncompleteChecks) { |
| if (Node->isIncomplete()) { |
| ++MissedIncompleteChecks; |
| return; |
| } |
| } |
| // Get the pool handle associated with this pointer. If there is no pool |
| // handle, use a NULL pointer value and let the runtime deal with it. |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F); |
| Value *PH = getPoolHandle(V, F, *FI); |
| #ifdef DEBUG |
| std::cerr << "LLVA: addLSChecks: Pool " << PH << " Node " << Node << std::endl; |
| #endif |
| // FIXME: We cannot handle checks to global or stack positions right now. |
| if ((!PH) || (Node->isAllocaNode()) || (Node->isGlobalNode())) { |
| ++NullChecks; |
| if (!PH) ++MissedNullChecks; |
| if (Node->isAllocaNode()) ++MissedStackChecks; |
| if (Node->isGlobalNode()) ++MissedGlobalChecks; |
| |
| // Don't bother to insert the NULL check unless the user asked |
| if (!EnableNullChecks) |
| return; |
| PH = Constant::getNullValue(PointerType::getUnqual(Type::Int8Ty)); |
| } else { |
| // |
| // Only add the pool check if the pool is a global value or it |
| // belongs to the same basic block. |
| // |
| if (isa<GlobalValue>(PH)) { |
| ++FullChecks; |
| } else if (isa<Instruction>(PH)) { |
| Instruction * IPH = (Instruction *)(PH); |
| if (IPH->getParent() == I->getParent()) { |
| // |
| // If the instructions belong to the same basic block, ensure that |
| // the pool dominates the load/store. |
| // |
| Instruction * IP = IPH; |
| for (IP=IPH; (IP->isTerminator()) || (IP == I); IP=IP->getNext()) { |
| ; |
| } |
| if (IP == I) |
| ++FullChecks; |
| else { |
| ++MissChecks; |
| return; |
| } |
| } else { |
| ++MissChecks; |
| return; |
| } |
| } else { |
| ++MissChecks; |
| return; |
| } |
| } |
| // Create instructions to cast the checked pointer and the checked pool |
| // into sbyte pointers. |
| CastInst *CastVI = |
| CastInst::createPointerCast(V, |
| PointerType::getUnqual(Type::Int8Ty), "node.lscasted", I); |
| CastInst *CastPHI = |
| CastInst::createPointerCast(PH, |
| PointerType::getUnqual(Type::Int8Ty), "poolhandle.lscasted", I); |
| |
| // Create the call to poolcheck |
| std::vector<Value *> args(1,CastPHI); |
| args.push_back(CastVI); |
| CallInst::Create(PoolCheck,args,"", I); |
| } |
| } |
| |
| void InsertPoolChecks::addLoadStoreChecks(Module &M){ |
| Module::iterator mI = M.begin(), mE = M.end(); |
| for ( ; mI != mE; ++mI) { |
| Function *F = mI; |
| for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { |
| if (LoadInst *LI = dyn_cast<LoadInst>(&*I)) { |
| Value *P = LI->getPointerOperand(); |
| addLSChecks(P, LI, F); |
| } else if (StoreInst *SI = dyn_cast<StoreInst>(&*I)) { |
| Value *P = SI->getPointerOperand(); |
| addLSChecks(P, SI, F); |
| } else if (ICmpInst *CmpI = dyn_cast<ICmpInst>(&*I)) { |
| switch (CmpI->getPredicate()) { |
| ICmpInst::Predicate::ICMP_EQ: |
| ICmpInst::Predicate::ICMP_NE: |
| // Replace all pointer operands with the getActualValue() call |
| assert ((CmpI->getNumOperands() == 2) && |
| "nmber of operands for CmpI different from 2 "); |
| if (isa<PointerType>(CmpI->getOperand(0)->getType())) { |
| // we need to insert a call to getactualvalue |
| // First get the poolhandle for the pointer |
| // TODO: We don't have a working getactualvalue(), so don't waste |
| // time calling it. |
| if ((!isa<ConstantPointerNull>(CmpI->getOperand(0))) && |
| (!isa<ConstantPointerNull>(CmpI->getOperand(1)))) { |
| addGetActualValue(CmpI, 0); |
| addGetActualValue(CmpI, 1); |
| } |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| } |
| } |
| } |
| #else |
| |
| // |
| // Method: addLSChecks() |
| // |
| // Inputs: |
| // Vnew - The pointer operand of the load/store instruction. |
| // V - ? |
| // Instruction - The load or store instruction |
| // F - The parent function of the instruction |
| // |
| void InsertPoolChecks::addLSChecks(Value *Vnew, const Value *V, Instruction *I, Function *F) { |
| |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F); |
| Value *PH = getPoolHandle(V, F, *FI ); |
| DSNode* Node = getDSNode(V, F); |
| if (!PH) { |
| return; |
| } |
| |
| if (isa<ConstantPointerNull>(PH)) { |
| //we have a collapsed/Unknown pool |
| Value *PH = getPoolHandle(V, F, *FI, true); |
| assert (PH && "Null pool handle!\n"); |
| } |
| |
| // Do not perform checks on incomplete nodes |
| if (Node && (Node->isIncompleteNode())) return; |
| |
| if (Node && Node->isNodeCompletelyFolded()) { |
| if (dyn_cast<CallInst>(I)) { |
| // Get the globals list corresponding to the node |
| std::vector<Function *> FuncList; |
| Node->addFullFunctionList(FuncList); |
| std::vector<Function *>::iterator flI= FuncList.begin(), flE = FuncList.end(); |
| unsigned num = FuncList.size(); |
| if (flI != flE) { |
| const Type* csiType = Type::Int32Ty; |
| Value *NumArg = ConstantInt::get(csiType, num); |
| |
| CastInst *CastVI = |
| CastInst::createPointerCast (Vnew, |
| PointerType::getUnqual(Type::Int8Ty), "casted", I); |
| |
| std::vector<Value *> args(1, NumArg); |
| args.push_back(CastVI); |
| for (; flI != flE ; ++flI) { |
| Function *func = *flI; |
| CastInst *CastfuncI = |
| CastInst::createPointerCast (func, |
| PointerType::getUnqual(Type::Int8Ty), "casted", I); |
| args.push_back(CastfuncI); |
| } |
| CallInst::Create(FunctionCheck, args.begin(), args.end(), "", I); |
| } |
| } else { |
| CastInst *CastVI = |
| CastInst::createPointerCast (Vnew, |
| PointerType::getUnqual(Type::Int8Ty), "casted", I); |
| CastInst *CastPHI = |
| CastInst::createPointerCast (PH, |
| PointerType::getUnqual(Type::Int8Ty), "casted", I); |
| std::vector<Value *> args(1,CastPHI); |
| args.push_back(CastVI); |
| |
| CallInst::Create(PoolCheck,args.begin(), args.end(), "", I); |
| } |
| } |
| } |
| |
| |
| void InsertPoolChecks::addLoadStoreChecks(Module &M){ |
| Module::iterator mI = M.begin(), mE = M.end(); |
| for ( ; mI != mE; ++mI) { |
| Function *F = mI; |
| //here we check that we only do this on original functions |
| //and not the cloned functions, the cloned functions may not have the |
| //DSG |
| bool isClonedFunc = false; |
| if (paPass->getFuncInfo(*F)) |
| isClonedFunc = false; |
| else |
| isClonedFunc = true; |
| Function *Forig = F; |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F); |
| if (isClonedFunc) { |
| Forig = paPass->getOrigFunctionFromClone(F); |
| } |
| //we got the original function |
| |
| for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { |
| if (LoadInst *LI = dyn_cast<LoadInst>(&*I)) { |
| // We need to get the LI from the original function |
| Value *P = LI->getPointerOperand(); |
| if (isClonedFunc) { |
| assert (FI && "No FuncInfo for this function\n"); |
| assert((FI->MapValueToOriginal(LI)) && " not in the value map \n"); |
| const LoadInst *temp = dyn_cast<LoadInst>(FI->MapValueToOriginal(LI)); |
| assert(temp && " Instruction not there in the NewToOldValue map"); |
| const Value *Ptr = temp->getPointerOperand(); |
| addLSChecks(P, Ptr, LI, Forig); |
| } else { |
| addLSChecks(P, P, LI, Forig); |
| } |
| } else if (StoreInst *SI = dyn_cast<StoreInst>(&*I)) { |
| Value *P = SI->getPointerOperand(); |
| if (isClonedFunc) { |
| std::cerr << *(SI) << std::endl; |
| #if 0 |
| assert(FI->NewToOldValueMap.count(SI) && " not in the value map \n"); |
| #else |
| assert((FI->MapValueToOriginal(SI)) && " not in the value map \n"); |
| #endif |
| #if 0 |
| const StoreInst *temp = dyn_cast<StoreInst>(FI->NewToOldValueMap[SI]); |
| #else |
| const StoreInst *temp = dyn_cast<StoreInst>(FI->MapValueToOriginal(SI)); |
| #endif |
| assert(temp && " Instruction not there in the NewToOldValue map"); |
| const Value *Ptr = temp->getPointerOperand(); |
| addLSChecks(P, Ptr, SI, Forig); |
| } else { |
| addLSChecks(P, P, SI, Forig); |
| } |
| } else if (CallInst *CI = dyn_cast<CallInst>(&*I)) { |
| Value *FunctionOp = CI->getOperand(0); |
| if (!isa<Function>(FunctionOp)) { |
| std::cerr << "JTC: LIC: " << F->getName() << " : " << *(CI->getOperand(0)) << std::endl; |
| if (isClonedFunc) { |
| assert(FI->MapValueToOriginal(CI) && " not in the value map \n"); |
| const CallInst *temp = dyn_cast<CallInst>(FI->MapValueToOriginal(CI)); |
| assert(temp && " Instruction not there in the NewToOldValue map"); |
| const Value* FunctionOp1 = temp->getOperand(0); |
| addLSChecks(FunctionOp, FunctionOp1, CI, Forig); |
| } else { |
| addLSChecks(FunctionOp, FunctionOp, CI, Forig); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| #endif |
| |
| void InsertPoolChecks::addGetElementPtrChecks (BasicBlock * BB) { |
| std::set<Instruction *> * UnsafeGetElemPtrs = abcPass->getUnsafeGEPs (BB); |
| if (!UnsafeGetElemPtrs) |
| return; |
| std::set<Instruction *>::const_iterator iCurrent = UnsafeGetElemPtrs->begin(), |
| iEnd = UnsafeGetElemPtrs->end(); |
| for (; iCurrent != iEnd; ++iCurrent) { |
| // We have the GetElementPtr |
| if (!isa<GetElementPtrInst>(*iCurrent)) { |
| //Then this must be a function call |
| //FIXME, get strcpy and others from the backup dir and adjust them for LLVA |
| //Right now I just add memset &llva_memcpy for LLVA |
| // std::cerr << " function call \n"; |
| #ifdef LLVA_KERNEL |
| CallInst *CI = dyn_cast<CallInst>(*iCurrent); |
| if (CI && (!DisableIntrinsicChecks)) { |
| Value *Fop = CI->getOperand(0); |
| Function *F = CI->getParent()->getParent(); |
| if (Fop->getName() == "llva_memcpy") { |
| Value *PH = getPoolHandle(CI->getOperand(1), F); |
| Instruction *InsertPt = CI; |
| if (!PH) { |
| ++NullChecks; |
| ++MissedNullChecks; |
| |
| // Don't bother to insert the NULL check unless the user asked |
| if (!EnableNullChecks) |
| continue; |
| PH = Constant::getNullValue(PointerType::getUnqual(Type::Int8Ty)); |
| } |
| CastInst *CastCIUint = |
| CastInst::createPointerCast(CI->getOperand(1), Type::Int32Ty, "node.lscasted", InsertPt); |
| CastInst *CastCIOp3 = |
| CastInst::createZExtOrBitCast(CI->getOperand(3), Type::Int32Ty, "node.lscasted", InsertPt); |
| Instruction *Bop = BinaryOperator::create(Instruction::Add, CastCIUint, |
| CastCIOp3, "memcpyadd",InsertPt); |
| |
| // Create instructions to cast the checked pointer and the checked pool |
| // into sbyte pointers. |
| CastInst *CastSourcePointer = |
| CastInst::createPointerCast(CI->getOperand(1), |
| PointerType::getUnqual(Type::Int8Ty), "memcpy.1.casted", InsertPt); |
| CastInst *CastCI = |
| CastInst::createPointerCast(Bop, |
| PointerType::getUnqual(Type::Int8Ty), "mempcy.2.casted", InsertPt); |
| CastInst *CastPHI = |
| CastInst::createPointerCast(PH, |
| PointerType::getUnqual(Type::Int8Ty), "poolhandle.lscasted", InsertPt); |
| |
| // Create the call to poolcheck |
| std::vector<Value *> args(1,CastPHI); |
| args.push_back(CastSourcePointer); |
| args.push_back(CastCI); |
| CallInst::Create(PoolCheckArray,args.begin(), args.end(),"", InsertPt); |
| #if 0 |
| } else if (Fop->getName() == "memset") { |
| Value *PH = getPoolHandle(CI->getOperand(1), F); |
| Instruction *InsertPt = CI->getNext(); |
| if (!PH) { |
| NullChecks++; |
| // Don't bother to insert the NULL check unless the user asked |
| if (!EnableNullChecks) |
| continue; |
| PH = Constant::getNullValue(PointerType::getUnqual(Type::Int8Ty)); |
| } |
| CastInst *CastCIUint = |
| CastInst::createPointerCast(CI, Type::Int32Ty, "node.lscasted", InsertPt); |
| CastInst *CastCIOp3 = |
| CastInst::createZExtOrBitCast(CI->getOperand(3), Type::Int32Ty, "node.lscasted", InsertPt); |
| Instruction *Bop = BinaryOperator::create(Instruction::Add, CastCIUint, |
| CastCIOp3, "memsetadd",InsertPt); |
| |
| // Create instructions to cast the checked pointer and the checked pool |
| // into sbyte pointers. |
| CastInst *CastSourcePointer = |
| CastInst::createPointerCast(CI->getOperand(1), |
| PointerType::getUnqual(Type::Int8Ty), "memset.1.casted", InsertPt); |
| CastInst *CastCI = |
| CastInst::createPointerCast(Bop, |
| PointerType::getUnqual(Type::Int8Ty), "memset.2.casted", InsertPt); |
| CastInst *CastPHI = |
| CastInst::createPointerCast(PH, |
| PointerType::getUnqual(Type::Int8Ty), "poolhandle.lscasted", InsertPt); |
| |
| // Create the call to poolcheck |
| std::vector<Value *> args(1,CastPHI); |
| args.push_back(CastSourcePointer); |
| args.push_back(CastCI); |
| CallInst::Create(PoolCheckArray,args,"", InsertPt); |
| #endif |
| } |
| } |
| #endif |
| continue; |
| } |
| GetElementPtrInst *GEP = cast<GetElementPtrInst>(*iCurrent); |
| Function *F = GEP->getParent()->getParent(); |
| // Now we need to decide if we need to pass in the alignmnet |
| //for the poolcheck |
| // if (getDSNodeOffset(GEP->getPointerOperand(), F)) { |
| // std::cerr << " we don't handle middle of structs yet\n"; |
| //assert(!getDSNodeOffset(GEP->getPointerOperand(), F) && " we don't handle middle of structs yet\n"); |
| // ++MissChecks; |
| // continue; |
| // } |
| |
| #ifndef LLVA_KERNEL |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F); |
| Instruction *Casted = GEP; |
| #if 0 |
| // |
| // JTC: Disabled. I'm not sure why we would look up a cloned value when |
| // processing an old value. |
| // |
| std::cerr << "Parent: " << GEP->getParent()->getParent()->getName() << std::endl; |
| std::cerr << "Ins : " << *GEP << std::endl; |
| if (!FI->ValueMap.empty()) { |
| assert(FI->ValueMap.count(GEP) && "Instruction not in the value map \n"); |
| Instruction *temp = dyn_cast<Instruction>(FI->ValueMap[GEP]); |
| assert(temp && " Instruction not there in the Value map"); |
| Casted = temp; |
| } |
| #endif |
| if (GetElementPtrInst *GEPNew = dyn_cast<GetElementPtrInst>(Casted)) { |
| Value *PH = getPoolHandle(GEP, F, *FI); |
| if (PH && isa<ConstantPointerNull>(PH)) continue; |
| if (!PH) { |
| Value *PointerOperand = GEPNew->getPointerOperand(); |
| if (ConstantExpr *cExpr = dyn_cast<ConstantExpr>(PointerOperand)) { |
| if ((cExpr->getOpcode() == Instruction::Trunc) || |
| (cExpr->getOpcode() == Instruction::ZExt) || |
| (cExpr->getOpcode() == Instruction::SExt) || |
| (cExpr->getOpcode() == Instruction::FPToUI) || |
| (cExpr->getOpcode() == Instruction::FPToSI) || |
| (cExpr->getOpcode() == Instruction::UIToFP) || |
| (cExpr->getOpcode() == Instruction::SIToFP) || |
| (cExpr->getOpcode() == Instruction::FPTrunc) || |
| (cExpr->getOpcode() == Instruction::FPExt) || |
| (cExpr->getOpcode() == Instruction::PtrToInt) || |
| (cExpr->getOpcode() == Instruction::IntToPtr) || |
| (cExpr->getOpcode() == Instruction::BitCast)) |
| PointerOperand = cExpr->getOperand(0); |
| } |
| if (GlobalVariable *GV = dyn_cast<GlobalVariable>(PointerOperand)) { |
| if (const ArrayType *AT = dyn_cast<ArrayType>(GV->getType()->getElementType())) { |
| // We need to insert an actual check. It could be a select |
| // instruction. |
| // First get the size. |
| // This only works for one or two dimensional arrays. |
| if (GEPNew->getNumOperands() == 2) { |
| Value *secOp = GEPNew->getOperand(1); |
| if (secOp->getType() != Type::Int32Ty) { |
| secOp = CastInst::createSExtOrBitCast(secOp, Type::Int32Ty, |
| secOp->getName()+".ec.casted", Casted); |
| } |
| |
| const Type* csiType = Type::Int32Ty; |
| std::vector<Value *> args(1,secOp); |
| args.push_back(ConstantInt::get(csiType,AT->getNumElements())); |
| CallInst::Create(ExactCheck,args.begin(), args.end(), "", Casted); |
| DEBUG(std::cerr << "Inserted exact check call Instruction \n"); |
| continue; |
| } else if (GEPNew->getNumOperands() == 3) { |
| if (ConstantInt *COP = dyn_cast<ConstantInt>(GEPNew->getOperand(1))) { |
| // FIXME: assuming that the first array index is 0 |
| assert((COP->getZExtValue() == 0) && "non zero array index\n"); |
| Value * secOp = GEPNew->getOperand(2); |
| if (secOp->getType() != Type::Int32Ty) { |
| secOp = CastInst::createSExtOrBitCast(secOp, Type::Int32Ty, |
| secOp->getName()+".ec2.casted", Casted); |
| } |
| std::vector<Value *> args(1,secOp); |
| const Type* csiType = Type::Int32Ty; |
| args.push_back(ConstantInt::get(csiType,AT->getNumElements())); |
| CallInst::Create(ExactCheck, args.begin(), args.end(), "", getNextInst(Casted)); |
| continue; |
| } else { |
| // Handle non constant index two dimensional arrays later |
| abort(); |
| } |
| } else { |
| // Handle Multi dimensional cases later |
| DEBUG(std::cerr << "WARNING: Handle multi dimensional globals later\n"); |
| (*iCurrent)->dump(); |
| } |
| } |
| DEBUG(std::cerr << " Global variable ok \n"); |
| } |
| |
| // These must be real unknowns and they will be handled anyway |
| // std::cerr << " WARNING, DID NOT HANDLE \n"; |
| // (*iCurrent)->dump(); |
| continue ; |
| } else { |
| // |
| // Determine if this is a pool belonging to a cloned version of the |
| // function. If so, do not add a pool check. |
| // |
| if (Instruction * InsPH = dyn_cast<Instruction>(PH)) { |
| if ((InsPH->getParent()->getParent()) != |
| (Casted->getParent()->getParent())) |
| return; |
| } |
| |
| BasicBlock::iterator InsertPt = Casted; |
| ++InsertPt; |
| Casted = castTo (Casted, |
| PointerType::getUnqual(Type::Int8Ty), |
| (Casted)->getName()+".pc.casted", |
| InsertPt); |
| |
| Value * CastedSrc = castTo (GEP->getPointerOperand(), |
| PointerType::getUnqual(Type::Int8Ty), |
| (Casted)->getName()+".pcsrc.casted", |
| InsertPt); |
| |
| Value *CastedPH = castTo (PH, |
| PointerType::getUnqual(Type::Int8Ty), |
| "jtcph", |
| InsertPt); |
| std::vector<Value *> args(1, CastedPH); |
| args.push_back(CastedSrc); |
| args.push_back(Casted); |
| |
| // Insert it |
| DSNode * Node = getDSNode (GEP, F); |
| if (Node->isIncompleteNode()) |
| CallInst::Create(PoolCheckArrayUI, args.begin(), args.end(), |
| "", InsertPt); |
| else |
| CallInst::Create(PoolCheckArray, args.begin(), args.end(), |
| "", InsertPt); |
| DEBUG(std::cerr << "inserted instrcution \n"); |
| } |
| } |
| #else |
| // |
| // Get the pool handle associated with the pointer operand. |
| // |
| Value *PH = getPoolHandle(GEP->getPointerOperand(), F); |
| GetElementPtrInst *GEPNew = GEP; |
| Instruction *Casted = GEP; |
| |
| DSGraph & TDG = TDPass->getDSGraph(*F); |
| DSNode * Node = TDG.getNodeForValue(GEP).getNode(); |
| |
| DEBUG(std::cerr << "LLVA: addGEPChecks: Pool " << PH << " Node "); |
| DEBUG(std::cerr << Node << std::endl); |
| |
| Value *PointerOperand = GEPNew->getPointerOperand(); |
| if (ConstantExpr *cExpr = dyn_cast<ConstantExpr>(PointerOperand)) { |
| if (cExpr->getOpcode() == Instruction::Cast) |
| PointerOperand = cExpr->getOperand(0); |
| } |
| if (GlobalVariable *GV = dyn_cast<GlobalVariable>(PointerOperand)) { |
| if (const ArrayType *AT = dyn_cast<ArrayType>(GV->getType()->getElementType())) { |
| // we need to insert an actual check |
| // It could be a select instruction |
| // First get the size |
| // This only works for one or two dimensional arrays |
| if (GEPNew->getNumOperands() == 2) { |
| Value *secOp = GEPNew->getOperand(1); |
| if (secOp->getType() != Type::Int32Ty) { |
| secOp = CastInst::createSExtOrBitCast(secOp, Type::Int32Ty, |
| secOp->getName()+".ec3.casted", Casted); |
| } |
| |
| std::vector<Value *> args(1,secOp); |
| const Type* csiType = Type::getPrimitiveType(Type::Int32TyID); |
| args.push_back(ConstantInt::get(csiType,AT->getNumElements())); |
| CallInst *newCI = CallInst::Create(ExactCheck,args,"", Casted); |
| ++BoundChecks; |
| // DEBUG(std::cerr << "Inserted exact check call Instruction \n"); |
| continue; |
| } else if (GEPNew->getNumOperands() == 3) { |
| if (ConstantInt *COP = dyn_cast<ConstantInt>(GEPNew->getOperand(1))) { |
| //FIXME assuming that the first array index is 0 |
| assert((COP->getZExtValue() == 0) && "non zero array index\n"); |
| Value * secOp = GEPNew->getOperand(2); |
| if (secOp->getType() != Type::Int32Ty) { |
| secOp = CastInst::createSExtOrBitCast(secOp, Type::Int32Ty, |
| secOp->getName()+".ec4.casted", Casted); |
| } |
| std::vector<Value *> args(1,secOp); |
| const Type* csiType = Type::getPrimitiveType(Type::Int32TyID); |
| args.push_back(ConstantInt::get(csiType,AT->getNumElements())); |
| CallInst *newCI = CallInst::Create(ExactCheck,args,"", Casted->getNext()); |
| ++BoundChecks; |
| continue; |
| } else { |
| //Handle non constant index two dimensional arrays later |
| abort(); |
| } |
| } else { |
| //Handle Multi dimensional cases later |
| std::cerr << "WARNING: Handle multi dimensional globals later\n"; |
| (*iCurrent)->dump(); |
| ++MissedMultDimArrayChecks; |
| } |
| DEBUG(std::cerr << " Global variable ok \n"); |
| } |
| } |
| |
| #if 0 |
| //No checks for incomplete nodes |
| if (!EnableIncompleteChecks) { |
| if (Node->isIncomplete()) { |
| ++MissedNullChecks; |
| continue; |
| } |
| } |
| #endif |
| |
| // |
| // We cannot insert an exactcheck(). Insert a pool check. |
| // |
| if (!PH) { |
| DEBUG(std::cerr << "missing GEP check: Null PH: " << GEP << "\n"); |
| ++NullChecks; |
| if (!PH) ++MissedNullChecks; |
| |
| // Don't bother to insert the NULL check unless the user asked |
| if (!EnableNullChecks) |
| { |
| continue; |
| } |
| PH = Constant::getNullValue(PointerType::getUnqual(Type::Int8Ty)); |
| } else { |
| // |
| // Determine whether the pool handle dominates the pool check. |
| // If not, then don't insert it. |
| // |
| |
| // |
| // FIXME: |
| // This domination check is too restrictive; it eliminates pools that do |
| // dominate but are outside of the current basic block. |
| // |
| // Only add the pool check if the pool is a global value or it belongs |
| // to the same basic block. |
| // |
| if (isa<GlobalValue>(PH)) { |
| ++FullChecks; |
| } else if (isa<Instruction>(PH)) { |
| Instruction * IPH = (Instruction *)(PH); |
| if (IPH->getParent() == Casted->getParent()) { |
| // |
| // If the instructions belong to the same basic block, ensure that |
| // the pool dominates the load/store. |
| // |
| Instruction * IP = IPH; |
| for (IP=IPH; (IP->isTerminator()) || (IP==Casted); IP=IP->getNext()) { |
| ; |
| } |
| if (IP == Casted) |
| ++FullChecks; |
| else { |
| ++MissChecks; |
| continue; |
| } |
| } else { |
| ++MissChecks; |
| continue; |
| } |
| } else { |
| ++MissChecks; |
| continue; |
| } |
| } |
| |
| // |
| // Regardless of the node type, always perform an accurate bounds check. |
| // |
| Instruction *InsertPt = Casted->getNext(); |
| if (Casted->getType() != PointerType::getUnqual(Type::Int8Ty)) { |
| Casted = CastInst::createPointerCast(Casted,PointerType::getUnqual(Type::Int8Ty), |
| (Casted)->getName()+".pc2.casted",InsertPt); |
| } |
| Instruction *CastedPointerOperand = CastInst::createPointerCast(PointerOperand, |
| PointerType::getUnqual(Type::Int8Ty), |
| PointerOperand->getName()+".casted",InsertPt); |
| Instruction *CastedPH = CastInst::createPointerCast(PH, |
| PointerType::getUnqual(Type::Int8Ty), |
| "ph",InsertPt); |
| std::vector<Value *> args(1, CastedPH); |
| args.push_back(CastedPointerOperand); |
| args.push_back(Casted); |
| CallInst * newCI = CallInst::Create(PoolCheckArray,args, "",InsertPt); |
| #endif |
| } |
| } |
| |
| void InsertPoolChecks::addPoolCheckProto(Module &M) { |
| const Type * VoidPtrType = PointerType::getUnqual(Type::Int8Ty); |
| /* |
| const Type *PoolDescType = ArrayType::get(VoidPtrType, 50); |
| // StructType::get(make_vector<const Type*>(VoidPtrType, VoidPtrType, |
| // Type::Int32Ty, Type::Int32Ty, 0)); |
| const Type * PoolDescTypePtr = PointerType::getUnqual(PoolDescType); |
| */ |
| |
| std::vector<const Type *> Arg(1, VoidPtrType); |
| Arg.push_back(VoidPtrType); |
| FunctionType *PoolCheckTy = |
| FunctionType::get(Type::VoidTy,Arg, false); |
| PoolCheck = M.getOrInsertFunction("poolcheck", PoolCheckTy); |
| |
| std::vector<const Type *> Arg2(1, VoidPtrType); |
| Arg2.push_back(VoidPtrType); |
| Arg2.push_back(VoidPtrType); |
| FunctionType *PoolCheckArrayTy = |
| FunctionType::get(Type::VoidTy,Arg2, false); |
| PoolCheckArray = M.getOrInsertFunction("boundscheck", PoolCheckArrayTy); |
| PoolCheckArrayUI = M.getOrInsertFunction("boundscheckui", PoolCheckArrayTy); |
| |
| std::vector<const Type *> FArg2(1, Type::Int32Ty); |
| FArg2.push_back(Type::Int32Ty); |
| FunctionType *ExactCheckTy = FunctionType::get(Type::VoidTy, FArg2, false); |
| ExactCheck = M.getOrInsertFunction("exactcheck", ExactCheckTy); |
| |
| std::vector<const Type *> FArg3(1, Type::Int32Ty); |
| FArg3.push_back(VoidPtrType); |
| FArg3.push_back(VoidPtrType); |
| FunctionType *FunctionCheckTy = FunctionType::get(Type::VoidTy, FArg3, true); |
| FunctionCheck = M.getOrInsertFunction("funccheck", FunctionCheckTy); |
| |
| std::vector<const Type*> FArg5(1, VoidPtrType); |
| FArg5.push_back(VoidPtrType); |
| FunctionType *GetActualValueTy = FunctionType::get(VoidPtrType, FArg5, false); |
| GetActualValue=M.getOrInsertFunction("pchk_getActualValue", GetActualValueTy); |
| |
| std::vector<const Type*> FArg6(1, VoidPtrType); |
| FArg6.push_back(VoidPtrType); |
| FunctionType *StackFreeTy = FunctionType::get(VoidPtrType, FArg6, false); |
| StackFree=M.getOrInsertFunction("poolunregister", StackFreeTy); |
| } |
| |
| DSNode* InsertPoolChecks::getDSNode(const Value *V, Function *F) { |
| #ifndef LLVA_KERNEL |
| DSGraph &TDG = paPass->getDSGraph(*F); |
| #else |
| DSGraph &TDG = TDPass->getDSGraph(*F); |
| #endif |
| DSNode *DSN = TDG.getNodeForValue((Value *)V).getNode(); |
| return DSN; |
| } |
| |
| unsigned InsertPoolChecks::getDSNodeOffset(const Value *V, Function *F) { |
| #ifndef LLVA_KERNEL |
| DSGraph &TDG = paPass->getDSGraph(*F); |
| #else |
| DSGraph &TDG = TDPass->getDSGraph(*F); |
| #endif |
| return TDG.getNodeForValue((Value *)V).getOffset(); |
| } |
| #ifndef LLVA_KERNEL |
| Value * |
| InsertPoolChecks::getPoolHandle(const Value *V, Function *F, PA::FuncInfo &FI, |
| bool collapsed) { |
| #if 1 |
| // |
| // JTC: |
| // If this function has a clone, then try to grab the original. |
| // |
| if (!(paPass->getFuncInfo(*F))) |
| { |
| std::cerr << "PoolHandle: Getting original Function\n"; |
| F = paPass->getOrigFunctionFromClone(F); |
| assert (F && "No Function Information from Pool Allocation!\n"); |
| } |
| #endif |
| |
| // |
| // Get the DSNode for the value. |
| // |
| const DSNode *Node = getDSNode(V,F); |
| if (!Node) { |
| std::cerr << "JTC: Value " << *V << " has no DSNode!" << std::endl; |
| return 0; |
| } |
| |
| // Get the pool handle for this DSNode... |
| // assert(!Node->isUnknownNode() && "Unknown node \n"); |
| Type *VoidPtrType = PointerType::getUnqual(Type::Int8Ty); |
| const Type *PoolDescType = paPass->getPoolType(); |
| const Type *PoolDescPtrTy = PointerType::getUnqual(PoolDescType); |
| if (Node->isUnknownNode()) { |
| // |
| // FIXME: |
| // This should be in a top down pass or propagated like collapsed pools |
| // below . |
| // |
| if (!collapsed) { |
| #if 0 |
| assert(!getDSNodeOffset(V, F) && " we don't handle middle of structs yet\n"); |
| #else |
| if (getDSNodeOffset(V, F)) |
| std::cerr << "ERROR: we don't handle middle of structs yet" |
| << std::endl; |
| #endif |
| std::cerr << "JTC: PH: Null 1: " << *V << std::endl; |
| return Constant::getNullValue(PoolDescPtrTy); |
| } |
| } |
| |
| Value * PH = paPass->getPool (Node, *F); |
| map <Function *, set<Value *> > & |
| CollapsedPoolPtrs = efPass->CollapsedPoolPtrs; |
| |
| if (PH) { |
| // Check that the node pointed to by V in the TD DS graph is not |
| // collapsed |
| |
| if (!collapsed && CollapsedPoolPtrs.count(F)) { |
| Value *v = PH; |
| if (CollapsedPoolPtrs[F].find(PH) != CollapsedPoolPtrs[F].end()) { |
| #ifdef DEBUG |
| std::cerr << "Collapsed pools \n"; |
| #endif |
| std::cerr << "JTC: PH: Null 2: " << *V << std::endl; |
| return Constant::getNullValue(PoolDescPtrTy); |
| } else { |
| if (Argument * Arg = dyn_cast<Argument>(v)) |
| if ((Arg->getParent()) != F) |
| { |
| std::cerr << "JTC: PH: Null 3: " << *V << std::endl; |
| return Constant::getNullValue(PoolDescPtrTy); |
| } |
| return v; |
| } |
| } else { |
| if (Argument * Arg = dyn_cast<Argument>(PH)) |
| if ((Arg->getParent()) != F) |
| { |
| std::cerr << "JTC: PH: Null 4: " << *V << std::endl; |
| return Constant::getNullValue(PoolDescPtrTy); |
| } |
| return PH; |
| } |
| } |
| |
| std::cerr << "JTC: Value " << *V << " not in PoolDescriptor List!" << std::endl; |
| return 0; |
| } |
| #else |
| Value *InsertPoolChecks::getPoolHandle(const Value *V, Function *F) { |
| DSGraph &TDG = TDPass->getDSGraph(*F); |
| const DSNode *Node = TDG.getNodeForValue((Value *)V).getNode(); |
| // Get the pool handle for this DSNode... |
| // assert(!Node->isUnknownNode() && "Unknown node \n"); |
| // if (Node->isUnknownNode()) { |
| // return 0; |
| // } |
| if ((TDG.getPoolDescriptorsMap()).count(Node)) |
| return (TDG.getPoolDescriptorsMap()[Node]->getMetaPoolValue()); |
| return 0; |
| } |
| #endif |
| } |