blob: 95c0ed102ed441e6369ca27a8cedc1304a050a1f [file] [log] [blame]
#include "safecode/Config/config.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;
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
static Statistic<> NullChecks ("safecode",
"Poolchecks with NULL pool descriptor");
static Statistic<> FullChecks ("safecode",
"Poolchecks with non-NULL pool descriptor");
static Statistic<> MissChecks ("safecode",
"Poolchecks omitted due to bad pool descriptor");
static Statistic<> PoolChecks ("safecode", "Poolchecks Added");
static Statistic<> BoundChecks("safecode",
"Bounds checks inserted");
static Statistic<> MissedIncompleteChecks ("safecode",
"Poolchecks missed because of incompleteness");
static Statistic<> MissedMultDimArrayChecks ("safecode",
"Multi-dimensional array checks");
static Statistic<> MissedStackChecks ("safecode", "Missed stack checks");
static Statistic<> MissedGlobalChecks ("safecode", "Missed global checks");
static Statistic<> MissedNullChecks ("safecode", "Missed PD checks");
bool InsertPoolChecks::runOnModule(Module &M) {
cuaPass = &getAnalysis<ConvertUnsafeAllocas>();
// budsPass = &getAnalysis<CompleteBUDataStructures>();
#ifndef LLVA_KERNEL
paPass = &getAnalysis<PoolAllocate>();
equivPass = &(paPass->getECGraphs());
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);
//
// Update the statistics.
//
PoolChecks = NullChecks + FullChecks;
return true;
}
#ifndef LLVA_KERNEL
void InsertPoolChecks::registerGlobalArraysWithGlobalPools(Module &M) {
Function *MainFunc = M.getMainFunction();
if (MainFunc == 0 || MainFunc->isExternal()) {
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);
Function *PoolRegister = paPass->PoolRegister;
BasicBlock::iterator InsertPt = MainFunc->getEntryBlock().begin();
while ((isa<CallInst>(InsertPt)) || isa<CastInst>(InsertPt) || isa<AllocaInst>(InsertPt) || isa<BinaryOperator>(InsertPt)) ++InsertPt;
if (PH) {
Type *VoidPtrType = PointerType::get(Type::SByteTy);
Instruction *GVCasted = new CastInst(Argv,
VoidPtrType, Argv->getName()+"casted",InsertPt);
const Type* csiType = Type::getPrimitiveType(Type::UIntTyID);
Value *AllocSize = new CastInst(Argc,
csiType, Argc->getName()+"casted",InsertPt);
AllocSize = BinaryOperator::create(Instruction::Mul, AllocSize,
ConstantInt::get(csiType, 4), "sizetmp", InsertPt);
new CallInst(PoolRegister,
make_vector(PH, AllocSize, GVCasted, 0),
"", InsertPt);
} else {
std::cerr << "argv's pool descriptor is not present. \n";
// abort();
}
}
//Now iterate over globals and register all the arrays
Module::global_iterator GI = M.global_begin(), GE = M.global_end();
for ( ; GI != GE; ++GI) {
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(GI)) {
Type *VoidPtrType = PointerType::get(Type::SByteTy);
Type *PoolDescType = ArrayType::get(VoidPtrType, 50);
Type *PoolDescPtrTy = PointerType::get(PoolDescType);
if (GV->getType() != PoolDescPtrTy) {
DSGraph &G = equivPass->getGlobalsGraph();
DSNode *DSN = G.getNodeForValue(GV).getNode();
if ((isa<ArrayType>(GV->getType()->getElementType())) || DSN->isNodeCompletelyFolded()) {
Value * AllocSize;
const Type* csiType = Type::getPrimitiveType(Type::UIntTyID);
if (const ArrayType *AT = dyn_cast<ArrayType>(GV->getType()->getElementType())) {
//std::cerr << "found global \n";
AllocSize = ConstantInt::get(csiType,
(AT->getNumElements() * TD->getTypeSize(AT->getElementType())));
} else {
AllocSize = ConstantInt::get(csiType, TD->getTypeSize(GV->getType()));
}
Function *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)) ++InsertPt;
std::map<const DSNode *, Value *>::iterator I = paPass->GlobalNodes.find(DSN);
if (I != paPass->GlobalNodes.end()) {
Value *PH = I->second;
Instruction *GVCasted = new CastInst(GV,
VoidPtrType, GV->getName()+"casted",InsertPt);
new CallInst(PoolRegister,
make_vector(PH, AllocSize, GVCasted, 0),
"", InsertPt);
} else {
std::cerr << "pool descriptor not present \n ";
abort();
}
}
}
}
}
}
#endif
void InsertPoolChecks::addPoolChecks(Module &M) {
if (!DisableGEPChecks) addGetElementPtrChecks(M);
if (!DisableLSChecks) addLoadStoreChecks(M);
}
#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.
Value *PH = getPoolHandle(V, F);
#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::get(Type::SByteTy));
} 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 =
new CastInst(V,
PointerType::get(Type::SByteTy), "node.lscasted", I);
CastInst *CastPHI =
new CastInst(PH,
PointerType::get(Type::SByteTy), "poolhandle.lscasted", I);
// Create the call to poolcheck
std::vector<Value *> args(1,CastPHI);
args.push_back(CastVI);
new CallInst(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
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;
} else {
if (PH && isa<ConstantPointerNull>(PH)) {
//we have a collapsed/Unknown pool
Value *PH = getPoolHandle(V, F, *FI, true);
if (dyn_cast<CallInst>(I)) {
// GEt the globals list corresponding to the node
return;
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::getPrimitiveType(Type::UIntTyID);
Value *NumArg = ConstantInt::get(csiType, num);
CastInst *CastVI =
new CastInst(Vnew,
PointerType::get(Type::SByteTy), "casted", I);
std::vector<Value *> args(1, NumArg);
args.push_back(CastVI);
for (; flI != flE ; ++flI) {
Function *func = *flI;
CastInst *CastfuncI =
new CastInst(func,
PointerType::get(Type::SByteTy), "casted", I);
args.push_back(CastfuncI);
}
new CallInst(FunctionCheck, args,"", I);
}
} else {
CastInst *CastVI =
new CastInst(Vnew,
PointerType::get(Type::SByteTy), "casted", I);
CastInst *CastPHI =
new CastInst(PH,
PointerType::get(Type::SByteTy), "casted", I);
std::vector<Value *> args(1,CastPHI);
args.push_back(CastVI);
new CallInst(PoolCheck,args,"", 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->NewToOldValueMap.count(LI) && " not in the value map \n");
const LoadInst *temp = dyn_cast<LoadInst>(FI->NewToOldValueMap[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) {
assert(FI->NewToOldValueMap.count(SI) && " not in the value map \n");
const StoreInst *temp = dyn_cast<StoreInst>(FI->NewToOldValueMap[SI]);
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)) {
if (isClonedFunc) {
assert(FI->NewToOldValueMap.count(CI) && " not in the value map \n");
const CallInst *temp = dyn_cast<CallInst>(FI->NewToOldValueMap[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(Module &M) {
std::vector<Instruction *> & UnsafeGetElemPtrs = cuaPass->getUnsafeGetElementPtrsFromABC();
std::vector<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::get(Type::SByteTy));
}
CastInst *CastCIUint =
new CastInst(CI->getOperand(1), Type::UIntTy, "node.lscasted", InsertPt);
CastInst *CastCIOp3 =
new CastInst(CI->getOperand(3), Type::UIntTy, "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 =
new CastInst(CI->getOperand(1),
PointerType::get(Type::SByteTy), "memcpy.1.casted", InsertPt);
CastInst *CastCI =
new CastInst(Bop,
PointerType::get(Type::SByteTy), "mempcy.2.casted", InsertPt);
CastInst *CastPHI =
new CastInst(PH,
PointerType::get(Type::SByteTy), "poolhandle.lscasted", InsertPt);
// Create the call to poolcheck
std::vector<Value *> args(1,CastPHI);
args.push_back(CastSourcePointer);
args.push_back(CastCI);
new CallInst(PoolCheckArray,args,"", 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::get(Type::SByteTy));
}
CastInst *CastCIUint =
new CastInst(CI, Type::UIntTy, "node.lscasted", InsertPt);
CastInst *CastCIOp3 =
new CastInst(CI->getOperand(3), Type::UIntTy, "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 =
new CastInst(CI->getOperand(1),
PointerType::get(Type::SByteTy), "memset.1.casted", InsertPt);
CastInst *CastCI =
new CastInst(Bop,
PointerType::get(Type::SByteTy), "memset.2.casted", InsertPt);
CastInst *CastPHI =
new CastInst(PH,
PointerType::get(Type::SByteTy), "poolhandle.lscasted", InsertPt);
// Create the call to poolcheck
std::vector<Value *> args(1,CastPHI);
args.push_back(CastSourcePointer);
args.push_back(CastCI);
new CallInst(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 (!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;
}
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::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::UIntTy) {
secOp = new CastInst(secOp, Type::UIntTy,
secOp->getName()+".ec.casted", Casted);
}
const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
std::vector<Value *> args(1,secOp);
args.push_back(ConstantInt::get(csiType,AT->getNumElements()));
new CallInst(ExactCheck,args,"", 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::UIntTy) {
secOp = new CastInst(secOp, Type::UIntTy,
secOp->getName()+".ec2.casted", Casted);
}
std::vector<Value *> args(1,secOp);
const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
args.push_back(ConstantInt::get(csiType,AT->getNumElements()));
new CallInst(ExactCheck, args, "", Casted->getNext());
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 {
if (Casted->getType() != PointerType::get(Type::SByteTy)) {
Casted = new CastInst(Casted,PointerType::get(Type::SByteTy),
(Casted)->getName()+".pc.casted",
(Casted)->getNext());
}
std::vector<Value *> args(1, PH);
args.push_back(Casted);
// Insert it
new CallInst(PoolCheck,args, "",Casted->getNext());
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::UIntTy) {
secOp = new CastInst(secOp, Type::UIntTy,
secOp->getName()+".ec3.casted", Casted);
}
std::vector<Value *> args(1,secOp);
const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
args.push_back(ConstantInt::get(csiType,AT->getNumElements()));
CallInst *newCI = new CallInst(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::UIntTy) {
secOp = new CastInst(secOp, Type::UIntTy,
secOp->getName()+".ec4.casted", Casted);
}
std::vector<Value *> args(1,secOp);
const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
args.push_back(ConstantInt::get(csiType,AT->getNumElements()));
CallInst *newCI = new CallInst(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.
//
// FIXME:
// Currently, we cannot register stack or global memory with pools. If
// the node is from alloc() or is a global, do not insert a poolcheck.
//
#if 0
if ((!PH) || (Node->isAllocaNode()) || (Node->isGlobalNode())) {
#else
if (!PH) {
#endif
++NullChecks;
if (!PH) ++MissedNullChecks;
#if 0
if (Node->isAllocaNode()) ++MissedStackChecks;
if (Node->isGlobalNode()) ++MissedGlobalChecks;
#endif
// Don't bother to insert the NULL check unless the user asked
if (!EnableNullChecks)
continue;
PH = Constant::getNullValue(PointerType::get(Type::SByteTy));
DEBUG(std::cerr << "missing a GEP check for" << GEP << "alloca case?\n");
} 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;
}
}
//
// If this is a complete node, insert a poolcheck.
// If this is an icomplete node, insert a poolcheckarray.
//
Instruction *InsertPt = Casted->getNext();
if (Casted->getType() != PointerType::get(Type::SByteTy)) {
Casted = new CastInst(Casted,PointerType::get(Type::SByteTy),
(Casted)->getName()+".pc2.casted",InsertPt);
}
Instruction *CastedPointerOperand = new CastInst(PointerOperand,
PointerType::get(Type::SByteTy),
PointerOperand->getName()+".casted",InsertPt);
Instruction *CastedPH = new CastInst(PH,
PointerType::get(Type::SByteTy),
"ph",InsertPt);
if (Node->isIncomplete()) {
std::vector<Value *> args(1, CastedPH);
args.push_back(CastedPointerOperand);
args.push_back(Casted);
CallInst * newCI = new CallInst(PoolCheckArray,args, "",InsertPt);
} else {
std::vector<Value *> args(1, CastedPH);
args.push_back(Casted);
CallInst * newCI = new CallInst(PoolCheck,args, "",InsertPt);
}
#endif
}
}
void InsertPoolChecks::addPoolCheckProto(Module &M) {
const Type * VoidPtrType = PointerType::get(Type::SByteTy);
/*
const Type *PoolDescType = ArrayType::get(VoidPtrType, 50);
// StructType::get(make_vector<const Type*>(VoidPtrType, VoidPtrType,
// Type::UIntTy, Type::UIntTy, 0));
const Type * PoolDescTypePtr = PointerType::get(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("poolcheckarray", PoolCheckArrayTy);
std::vector<const Type *> FArg2(1, Type::UIntTy);
FArg2.push_back(Type::IntTy);
FunctionType *ExactCheckTy = FunctionType::get(Type::VoidTy, FArg2, false);
ExactCheck = M.getOrInsertFunction("exactcheck", ExactCheckTy);
std::vector<const Type *> FArg3(1, Type::UIntTy);
FArg3.push_back(VoidPtrType);
FArg3.push_back(VoidPtrType);
FunctionType *FunctionCheckTy = FunctionType::get(Type::VoidTy, FArg3, true);
FunctionCheck = M.getOrInsertFunction("funccheck", FunctionCheckTy);
}
DSNode* InsertPoolChecks::getDSNode(const Value *V, Function *F) {
#ifndef LLVA_KERNEL
DSGraph &TDG = equivPass->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 = equivPass->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) {
const DSNode *Node = getDSNode(V,F);
// Get the pool handle for this DSNode...
// assert(!Node->isUnknownNode() && "Unknown node \n");
Type *VoidPtrType = PointerType::get(Type::SByteTy);
Type *PoolDescType = ArrayType::get(VoidPtrType, 50);
Type *PoolDescPtrTy = PointerType::get(PoolDescType);
if (!Node) {
return 0; //0 means there is no isse with the value, otherwise there will be a callnode
}
if (Node->isUnknownNode()) {
//FIXME this should be in a top down pass or propagated like collapsed pools below
if (!collapsed) {
assert(!getDSNodeOffset(V, F) && " we don't handle middle of structs yet\n");
return Constant::getNullValue(PoolDescPtrTy);
}
}
std::map<const DSNode*, Value*>::iterator I = FI.PoolDescriptors.find(Node);
map <Function *, set<Value *> > &
CollapsedPoolPtrs = efPass->CollapsedPoolPtrs;
if (I != FI.PoolDescriptors.end()) {
// Check that the node pointed to by V in the TD DS graph is not
// collapsed
if (!collapsed && CollapsedPoolPtrs.count(F)) {
Value *v = I->second;
if (CollapsedPoolPtrs[F].find(I->second) !=
CollapsedPoolPtrs[F].end()) {
#ifdef DEBUG
std::cerr << "Collapsed pools \n";
#endif
return Constant::getNullValue(PoolDescPtrTy);
} else {
return v;
}
} else {
return I->second;
}
}
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