blob: 85084d8768e3cd8d1961e150cd265b76e779d68a [file] [log] [blame]
//===- BaggyBoundChecks.cpp - Instrumentation for Baggy Bounds -------------------- --//
//
// The SAFECode Compiler
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass aligns globals and stack allocated values to the correct power to
// two boundary.
//
// FIXME: Alignment for Global Variables in LLVM 2.7 is a 16 bit field, and thus
// setting alignments larger than 2^16 fails. Have hacked it to work, by changing
// the alignment field to 32 bit in LLVM_SRC/include/llvm/GlobalValue.h.
// Should work fine on LLVM 2.8.
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "baggy-bound-checks"
#include "llvm/ADT/Statistic.h"
#include "llvm/Value.h"
#include "llvm/Constants.h"
#include "llvm/InstrTypes.h"
#include "llvm/Instruction.h"
#include "llvm/Instructions.h"
#include "llvm/Support/InstIterator.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "safecode/BaggyBoundsChecks.h"
#include "SCUtils.h"
#include <iostream>
#include <string>
#include <functional>
using namespace llvm;
NAMESPACE_SC_BEGIN
#define SLOT_SIZE 4
#define SLOT 16
// Identifier variable for the pass
char InsertBaggyBoundsChecks::ID = 0;
// Statistics
// Register the pass
static RegisterPass<InsertBaggyBoundsChecks> P("baggy bounds aligning",
"Baggy Bounds Transform");
//
// Method: runOnModule()
//
// Description:
// Entry point for this LLVM pass.
//
// Return value:
// true - The module was modified.
// false - The module was not modified.
//
bool
InsertBaggyBoundsChecks::runOnModule (Module & M) {
// Get prerequisite analysis resuilts.
TD = &getAnalysis<TargetData>();
intrinsicPass = &getAnalysis<InsertSCIntrinsic>();
const Type *Int8Type = Type::getInt8Ty(getGlobalContext());
const Type *Int32Type = Type::getInt32Ty(getGlobalContext());
// align globals, and pad
Module::global_iterator GI = M.global_begin(), GE = M.global_end();
for ( ; GI != GE; ++GI) {
GlobalVariable *GV = dyn_cast<GlobalVariable>(GI);
if (!GV) continue;
if (GV->isDeclaration()) {
// Don't bother to register external global variables
continue;
}
if (GV->getNumUses() == 0) continue;
if (GV->getSection() == "llvm.metadata") continue;
std::string name = GV->getName();
if (strncmp(name.c_str(), "llvm.", 5) == 0) continue;
if (strncmp(name.c_str(), "baggy.", 6) == 0) continue;
if (strncmp(name.c_str(), "__poolalloc", 11) == 0) continue;
if (SCConfig.svaEnabled()) {
// Linking fails when registering objects in section exitcall.exit
if (GV->getSection() == ".exitcall.exit") continue;
}
const Type * GlobalType = GV->getType()->getElementType();
unsigned long int i = TD->getTypeAllocSize(GlobalType);
unsigned int size= 0;
while((unsigned int)(1u<<size) < i) {
size++;
}
if(size < SLOT_SIZE) {
size = SLOT_SIZE;
}
unsigned int alignment = 1u << (size);
if(GV->getAlignment() > alignment) alignment = GV->getAlignment();
if(i == (unsigned)(1u<<size)) {
GV->setAlignment(1u<<size);
} else {
Type *newType1 = ArrayType::get(Int8Type, (alignment)-i);
StructType *newType = StructType::get(getGlobalContext(), GlobalType, newType1, NULL);
std::vector<Constant *> vals(2);
vals[0] = GV->getInitializer();
vals[1] = Constant::getNullValue(newType1);
Constant *c = ConstantStruct::get(newType, vals);
GlobalVariable *GV_new = new GlobalVariable(M, newType, GV->isConstant(), GV->getLinkage(),c, "baggy."+GV->getName());
GV_new->setAlignment(1u<<size);
Constant *Zero= ConstantInt::getSigned(Int32Type, 0);
Constant *idx[2] = {Zero, Zero};
Constant *init = ConstantExpr::getGetElementPtr(GV_new, idx, 2);
GV->replaceAllUsesWith(init);
}
}
//align allocas
Function *F = intrinsicPass->getIntrinsic("sc.pool_register_stack").F;
for (Value::use_iterator FU = F->use_begin(); FU != F->use_end(); ++FU) {
if (CallInst * CI = dyn_cast<CallInst>(FU)) {
std::set<Value *>Chain;
Value * RealOperand = intrinsicPass->getValuePointer (CI);
Value * PeeledOperand = peelCasts(RealOperand, Chain);
if(!isa<AllocaInst>(PeeledOperand)){
continue;
}
AllocaInst *AI = cast<AllocaInst>(PeeledOperand);
unsigned i = TD->getTypeAllocSize(AI->getAllocatedType());
unsigned char size = 0;
while((unsigned)(1<<size) < i) {
size++;
}
if(size < SLOT_SIZE) {
size = SLOT_SIZE;
}
if(i == (unsigned)(1u<<size)) {
AI->setAlignment(1u<<size);
} else {
BasicBlock::iterator InsertPt1 = AI;
Instruction * iptI1 = ++InsertPt1;
Type *newType1 = ArrayType::get(Int8Type, (1<<size)-i);
StructType *newType = StructType::get(getGlobalContext(), AI->getType()->getElementType(), newType1, NULL);
AllocaInst * AI_new = new AllocaInst(newType, 0,(1<<size) , "baggy."+AI->getName(), iptI1);
AI_new->setAlignment(1u<<size);
Value *Zero= ConstantInt::getSigned(Int32Type, 0);
Value *idx[3] = {Zero, Zero, NULL};
Instruction *init = GetElementPtrInst::Create(AI_new, idx + 0, idx + 1, Twine(""), iptI1);
init = GetElementPtrInst::Create(init, idx + 0, idx + 2, Twine(""), iptI1);
AI->replaceAllUsesWith(init);
AI->removeFromParent();
AI_new->setName(AI->getName());
}
}
}
// changes for register argv
Function *ArgvReg = intrinsicPass->getIntrinsic("sc.pool_argvregister").F;
if (!ArgvReg->use_empty()) {
assert (isa<PointerType>(ArgvReg->getReturnType()));
assert (ArgvReg->getNumUses() == 1);
CallInst *CI = cast<CallInst>(ArgvReg->use_begin());
Value *Argv = intrinsicPass->getValuePointer (CI);
BasicBlock::iterator I = CI;
I++;
BitCastInst *BI = new BitCastInst(CI, Argv->getType(), "argv_temp",cast<Instruction>(I));
std::vector<User *> Uses;
Value::use_iterator UI = Argv->use_begin();
for (; UI != Argv->use_end(); ++UI) {
if (Instruction * Use = dyn_cast<Instruction>(UI))
if (CI != Use) {
Uses.push_back (*UI);
}
}
while (Uses.size()) {
User *Use = Uses.back();
Uses.pop_back();
Use->replaceUsesOfWith (Argv, BI);
}
}
// align byval arguments
// FIXME Alignment does not work for byval arguments on x86_64(see LLVM Bug 6965, 9637)
// Fixed in r132764.
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++ I) {
if (I->isDeclaration()) continue;
if (I->hasName()) {
std::string Name = I->getName();
if ((Name.find ("__poolalloc") == 0) || (Name.find ("sc.") == 0)
|| Name.find("baggy.") == 0)
continue;
}
Function &F = cast<Function>(*I);
unsigned int i = 1;
for (Function::arg_iterator It = F.arg_begin(), E = F.arg_end(); It != E; ++It, ++i) {
if (It->hasByValAttr()) {
if(It->use_empty())
continue;
assert (isa<PointerType>(It->getType()));
const PointerType * PT = cast<PointerType>(It->getType());
const Type * ET = PT->getElementType();
unsigned AllocSize = TD->getTypeAllocSize(ET);
unsigned char size= 0;
while((unsigned)(1u<<size) < AllocSize) {
size++;
}
if(size < SLOT_SIZE) {
size = SLOT_SIZE;
}
unsigned int alignment = 1u << size;
if(AllocSize == alignment) {
F.addAttribute(i, llvm::Attribute::constructAlignmentFromInt(1u<<size));
for (Value::use_iterator FU = F.use_begin(); FU != F.use_end(); ++FU) {
if (CallInst * CI = dyn_cast<CallInst>(FU)) {
if (CI->getCalledFunction() == &F) {
CI->addAttribute(i, llvm::Attribute::constructAlignmentFromInt(1u<<size));
}
}
}
} else {
Type *newType1 = ArrayType::get(Int8Type, (alignment)-AllocSize);
StructType *newSType = StructType::get(getGlobalContext(), ET, newType1, NULL);
const FunctionType *FTy = F.getFunctionType();
// Construct the new Function Type
// Appends the struct Type at the beginning
std::vector<const Type*>TP;
TP.push_back(newSType->getPointerTo());
for(unsigned c = 0; c < FTy->getNumParams();c++) {
TP.push_back(FTy->getParamType(c));
}
//return type is same as that of original instruction
const FunctionType *NewFTy = FunctionType::get(FTy->getReturnType(), TP, false);
Function *NewF = Function::Create(NewFTy,
GlobalValue::InternalLinkage,
F.getNameStr() + ".TEST",
&M);
Function::arg_iterator NII = NewF->arg_begin();
NII->setName("Baggy");
++NII;
DenseMap<const Value*, Value*> ValueMap;
for (Function::arg_iterator II = F.arg_begin(); NII != NewF->arg_end(); ++II, ++NII) {
ValueMap[II] = NII;
NII->setName(II->getName());
}
// Perform the cloning.
SmallVector<ReturnInst*,100> Returns;
CloneFunctionInto(NewF, &F, ValueMap, Returns);
std::vector<Value*> fargs;
for(Function::arg_iterator ai = NewF->arg_begin(),
ae= NewF->arg_end(); ai != ae; ++ai) {
fargs.push_back(ai);
}
NII = NewF->arg_begin();
Value *zero = ConstantInt::get(Type::getInt32Ty(M.getContext()), 0);
Value *Idx[] = { zero, zero };
Instruction *InsertPoint;
for (BasicBlock::iterator insrt = NewF->front().begin(); isa<AllocaInst>(InsertPoint = insrt); ++insrt) {;}
GetElementPtrInst *GEPI = GetElementPtrInst::Create(cast<Value>(NII) , Idx, Idx + 2 , "", InsertPoint);
fargs.at(i)->uncheckedReplaceAllUsesWith(GEPI);
Function::const_arg_iterator I = F.arg_begin(),E = F.arg_end();
for (Function::const_arg_iterator I = F.arg_begin(),
E = F.arg_end(); I != E; ++I) {
NewF->getAttributes().addAttr(I->getArgNo() + 1, F.getAttributes().getParamAttributes(I->getArgNo() + 1));
}
NewF->setAttributes(NewF->getAttributes()
.addAttr(0, F.getAttributes()
.getRetAttributes()));
NewF->setAttributes(NewF->getAttributes()
.addAttr(~0, F.getAttributes()
.getFnAttributes()));
NewF->addAttribute(1, llvm::Attribute::constructAlignmentFromInt(1u<<size));
NewF->addAttribute(1, F.getAttributes().getParamAttributes(i));
// Change uses.
for (Value::use_iterator FU = F.use_begin(); FU != F.use_end(); ) {
if (CallInst * CI = dyn_cast<CallInst>(FU++)) {
if (CI->getCalledFunction() == &F) {
Function *Caller = CI->getParent()->getParent();
Instruction *InsertPoint;
for (BasicBlock::iterator insrt = Caller->front().begin(); isa<AllocaInst>(InsertPoint = insrt); ++insrt) {;}
AllocaInst *AINew = new AllocaInst(newSType, "", InsertPoint);
LoadInst *LINew = new LoadInst(CI->getOperand(i), "", CI);
GetElementPtrInst *GEPNew = GetElementPtrInst::Create(AINew,Idx ,Idx+2, "", CI);
new StoreInst(LINew, GEPNew, CI);
SmallVector<Value*, 8> Args;
Args.push_back(AINew);
for(unsigned j =1;j<CI->getNumOperands();j++) {
Args.push_back(CI->getOperand(j));
}
CallInst *CallI = CallInst::Create(NewF,Args.begin(), Args.end(),"", CI);
CallI->addAttribute(1, llvm::Attribute::constructAlignmentFromInt(1u<<size));
CallI->setCallingConv(CI->getCallingConv());
CI->replaceAllUsesWith(CallI);
CI->eraseFromParent();
}
}
}
}
}
}
}
return true;
}
NAMESPACE_SC_END