blob: 4b436abda7c5631c75dcf4feec78e6319ddec9aa [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 of
// two boundary.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "baggy-bound-checks"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/InstIterator.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/IR/TypeBuilder.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "safecode/BaggyBoundsChecks.h"
#include "safecode/Runtime/BBMetaData.h"
#include <iostream>
#include <set>
#include <string>
#include <functional>
static const unsigned SLOT_SIZE = 4;
static const unsigned SLOT = 16;
using namespace llvm;
namespace llvm {
// Identifier variable for the pass
char InsertBaggyBoundsChecks::ID = 0;
// Statistics
// Register the pass
static RegisterPass<InsertBaggyBoundsChecks> P("baggy bounds aligning",
"Baggy Bounds Transform");
//
// Function: findP2Size()
//
// Description:
// Find the power-of-two size that is greater than or equal to the specified
// size. Note that we will round small sizes up to SLOT_SIZE.
//
// Inputs:
// objectSize - The size of the original object in bytes.
//
// Return value:
// The exponent of the required size rounded to a power of two. For example,
// if we need 8 (2^3) bytes, we'd return 3.
//
static inline unsigned
findP2Size (unsigned long objectSize) {
unsigned int size = SLOT_SIZE;
while (((unsigned int)(1u<<size)) < objectSize) {
++size;
}
return size;
}
//
// Description:
// Define BBMetaData struct type using TypeBuilder template. So for global and
// stack variables, we can use this type to record their metadata when padding
// and aligning them.
//
template<bool xcompile> class TypeBuilder<BBMetaData, xcompile> {
public:
static StructType* get(LLVMContext& context) {
return StructType::get(
TypeBuilder<types::i<32>, xcompile>::get(context),
TypeBuilder<types::i<8>*, xcompile>::get(context),
NULL);
}
};
//
// Function: mustAdjustGlobalValue()
//
// Description:
// This function determines whether the global value must be adjusted for
// baggy bounds checking.
//
// Return value:
// 0 - The value does not need to be adjusted for baggy bounds checking.
// Otherwise, a pointer to the value is returned.
//
GlobalVariable *
mustAdjustGlobalValue (GlobalValue * V) {
//
// Only modify global variables. Everything else is left unchanged.
//
GlobalVariable * GV = dyn_cast<GlobalVariable>(V);
if (!GV) return 0;
//
// Don't adjust a global which has an opaque type.
//
if (StructType * ST = dyn_cast<StructType>(GV->getType()->getElementType())) {
if (ST->isOpaque()) {
return 0;
}
}
//
// Don't modify external global variables or variables with no uses.
//
//if (GV->isDeclaration()) {
//return 0;
// }
//
// Don't bother modifying the size of metadata.
//
if (GV->getSection() == "llvm.metadata") return 0;
std::string name = GV->getName();
if (strncmp(name.c_str(), "llvm.", 5) == 0) return 0;
if (strncmp(name.c_str(), "baggy.", 6) == 0) return 0;
if (strncmp(name.c_str(), "__poolalloc", 11) == 0) return 0;
// Don't modify globals in the exitcall section of the Linux kernel
if (GV->getSection() == ".exitcall.exit") return 0;
//
// Don't modify globals that are not emitted into the final executable.
//
if (GV->hasAvailableExternallyLinkage()) return 0;
return GV;
}
//
// Method: adjustGlobalValue()
//
// Description:
// This method adjusts the size and alignment of a global variable to suit
// baggy bounds checking.
//
void
InsertBaggyBoundsChecks::adjustGlobalValue (GlobalValue * V) {
//
// Only modify global variables. Everything else is left unchanged.
//
GlobalVariable * GV = mustAdjustGlobalValue(V);
if (!GV) return;
if (!GV->hasInitializer()) return;
//
// Find the greatest power-of-two size that is larger than the object's
// current size.
//
Type * GlobalType = GV->getType()->getElementType();
unsigned long objectSize = TD->getTypeAllocSize(GlobalType);
if (!objectSize) return;
unsigned long adjustedSize = objectSize + sizeof(BBMetaData);
unsigned int size = findP2Size (adjustedSize);
//
// Find the optimal alignment for the memory object. Note that we can use
// a larger alignment than needed.
//
unsigned int alignment = 1u << (size);
if (GV->getAlignment() > alignment) alignment = GV->getAlignment();
//
// Create a structure type. The first element will be the global memory
// object; the second will be an array of bytes that will pad the size out;
// the third will be the metadata for this object.
//
Type *Int8Type = Type::getInt8Ty(GV->getContext());
Type *newType1 = ArrayType::get (Int8Type, (1u<<size) - adjustedSize);
Type *metadataType = TypeBuilder<BBMetaData, false>::get(GV->getContext());
StructType *newType = StructType::get(GlobalType,
newType1,
metadataType,
NULL);
//
// Store the object's size into a metadata variable.
//
Type *Int32Type = Type::getInt32Ty (GV->getContext());
Type *Int8Ptr = PointerType::get(Int8Type, 0);
std::vector<Constant *> metaVals(2);
metaVals[0] = ConstantInt::get(Int32Type, objectSize);
metaVals[1] = Constant::getNullValue(Int8Ptr);
Constant *c = ConstantStruct::get((StructType *)metadataType, metaVals);
GlobalVariable *metaData = new GlobalVariable (*(GV->getParent()),
metadataType,
GV->isConstant(),
GlobalValue::LinkerPrivateLinkage,
c,
"meta." + GV->getName());
//
// Create a global initializer. The first element has the initializer of
// the original memory object, the second initializes the padding array,
// the third initializes the object's metadata using the metadata variable.
//
std::vector<Constant *> vals(3);
vals[0] = GV->getInitializer();
vals[1] = Constant::getNullValue(newType1);
vals[2] = metaData->getInitializer();
c = ConstantStruct::get(newType, vals);
//
// Create the new global memory object with the correct alignment.
//
GlobalValue::LinkageTypes LinkTy = GV->getLinkage();
if (GV->getLinkage() == GlobalValue::CommonLinkage)
LinkTy = GlobalValue::ExternalLinkage;
GlobalVariable *GV_new = new GlobalVariable (*(GV->getParent()),
newType,
GV->isConstant(),
LinkTy,
c,
"baggy." + GV->getName());
GV_new->copyAttributesFrom (GV);
GV_new->setAlignment(1u<<size);
GV_new->takeName (GV);
//
// Create a GEP expression that will represent the global value and replace
// all uses of the global value with the new constant GEP.
//
Value *Zero = ConstantInt::getSigned(Int32Type, 0);
Value *idx1[2] = {Zero, Zero};
Constant *init = ConstantExpr::getGetElementPtr(GV_new, idx1, 2);
GV->replaceAllUsesWith(init);
GV->eraseFromParent();
return;
}
//
// Method: adjustAlloca()
//
// Description:
// Modify the specified alloca instruction (if necessary) to give it the
// needed alignment and padding for baggy bounds checking.
//
void
InsertBaggyBoundsChecks::adjustAlloca (AllocaInst * AI) {
//
// Get the power-of-two size for the alloca.
//
unsigned objectSize = TD->getTypeAllocSize (AI->getAllocatedType());
//
// If the allocation allocates an array, then the allocated size is a
// multiplication.
//
if (AI->isArrayAllocation()) {
unsigned num = cast<ConstantInt>(AI->getOperand(0))->getZExtValue();
objectSize = objectSize * num;
}
unsigned adjustedSize = objectSize + sizeof(BBMetaData);
unsigned char size = findP2Size (adjustedSize);
//
// Create necessary types.
//
Type *Int8Type = Type::getInt8Ty (AI->getContext());
Type *Int32Type = Type::getInt32Ty (AI->getContext());
//
// Create a structure type. The first element will be the global memory
// object; the second will be an array of bytes that will pad the size out;
// the third will be the metadata for this object.
//
Type *newType1 = ArrayType::get(Int8Type, (1<<size) - adjustedSize);
Type *metadataType = TypeBuilder<BBMetaData, false>::get(AI->getContext());
Type *ty = AI->getType()->getElementType();
if (AI->isArrayAllocation()) {
ty = ArrayType::get(Int8Type, objectSize);
}
StructType *newType = StructType::get(ty,
newType1,
metadataType,
NULL);
//
// Create the new alloca instruction and set its alignment.
//
AllocaInst * AI_new = new AllocaInst (newType,
0,
(1<<size),
"baggy." + AI->getName(),
AI);
AI_new->setAlignment(1u<<size);
//
// Store the object size information into the medadata.
//
Value *Zero = ConstantInt::getSigned(Int32Type, 0);
Value *Two = ConstantInt::getSigned(Int32Type, 2);
Value *idx[3] = {Zero, Two, Zero};
Value *V = GetElementPtrInst::Create(AI_new, idx, Twine(""), AI);
new StoreInst(ConstantInt::get(Int32Type, objectSize), V, AI);
//
// Create a GEP that accesses the first element of this new structure.
//
Value *idx1[2] = {Zero, Zero};
Instruction *init = GetElementPtrInst::Create(AI_new,
idx1,
Twine(""),
AI);
AI->replaceAllUsesWith(init);
AI->removeFromParent();
AI_new->setName(AI->getName());
return;
}
//
// Method: adjustAllocasFor()
//
// Description:
// Look for allocas used in calls to the specified function and adjust their
// size and alignment for baggy bounds checking.
//
void
InsertBaggyBoundsChecks::adjustAllocasFor (Function * F) {
//
// If there is no such function, do nothing.
//
if (!F) return;
//
// Scan through all uses of the function and process any allocas used by it.
//
for (Value::use_iterator FU = F->use_begin(); FU != F->use_end(); ++FU) {
if (CallInst * CI = dyn_cast<CallInst>(*FU)) {
Value * Ptr = CI->getArgOperand(1)->stripPointerCasts();
if (AllocaInst * AI = dyn_cast<AllocaInst>(Ptr)){
adjustAlloca (AI);
}
}
}
return;
}
//
// Method: adjustArgv()
//
// Description:
// This function adjusts the argv strings for baggy bounds checking.
//
void
InsertBaggyBoundsChecks::adjustArgv (Function * F) {
//assert (F && "FIXME: Should not assume that argvregister is used!");
if (!F) return;
if (!F->use_empty()) {
assert (isa<PointerType>(F->getReturnType()));
assert (F->getNumUses() == 1);
CallInst *CI = cast<CallInst>(*(F->use_begin()));
Value *Argv = CI->getArgOperand(1);
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);
}
}
return;
}
//
// Function: mustCloneFunction()
//
// Description:
// This function determines whether a function must be cloned when
// dealing with byval argments for baggy bounds checking.
//
// Return value:
// 0 - The function does not need to be cloned for baggy bounds checking.
// 1 - The function need to be cloned for baggy bounds checking.
//
bool
mustCloneFunction (Function * F) {
if (F->isDeclaration()) return 0;
if (F->hasName()) {
std::string Name = F->getName();
if ((Name.find ("__poolalloc") == 0) || (Name.find ("sc.") == 0)
|| (Name.find("baggy.") == 0) || (Name.find(".TEST") != Name.npos))
return 0;
}
//
// Loop over all the arguments of the function. If one argument has the byval
// attribute and has use, then this function need to be cloned.
//
for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end();
I != E; ++I) {
if (I->hasByValAttr()) {
if(I->use_empty()) {
continue;
}
return 1;
}
}
return 0;
}
// Baggy bounds specific version of the CloneFunctionInto() function
// found in the llvm file lib/Transforms/Utils/CloneFunction.cpp.
//
// An outline of the processing of the function follows, with
// deltas from the original version noted:
//
// 1) Instead of setting the attributes of the new function, this
// version of cloneFunctionInto() simply verifies that:
//
// a) Non byval or unused parameters have identical type
// and alignment.
//
// b) used byval parameters must have different type and
// and alignment.
//
// c) The target type of the pointer type of each OldFunc
// used byval parameter must match the type of the first
// argument of the structure type that is the target type
// matching NewFunc parameter.
//
// c) VMap is setup as expected. Specifically, each OldFunc
// parameter must map to the matching parameter of the
// NewFunc.
//
// 2) Unlike the original version of the function, loop over all
// the used byval arguments in the old function. For each such
// argument,
//
// a) If we haven't created it already, create a basic block
// for the new function.
//
// b) Find the associated byval argument of the new function,
// We do this by simply looking it up in VMap[].
//
// c) construct a GEP instruction that computes a pointer
// to the copy of the byval argument in the old function
// that resides in the structure pointed to by the associated
// argument in the new function, and stores this value in a
// SSA virtual register.
//
// In passing, insert the GEP instruction into the new
// basic block we inserted in the new function.
//
// 3) Clone the basic blocks of the old function into the new, as
// per the original version of the function. Like the original
// version, transform the old arguments into references to
// the associated VMap values
//
// 4) Assuming it was created, add an unconditional branch from the
// end of the basic block created in 2) above to the first
// basic block cloned from the old function.
//
// JRM -- 2/5/12
//
void
InsertBaggyBoundsChecks::cloneFunctionInto(Function *NewFunc,
const Function *OldFunc,
ValueToValueMapTy &VMap,
bool ModuleLevelChanges,
SmallVectorImpl<ReturnInst*> &Returns,
const char *NameSuffix,
ClonedCodeInfo *CodeInfo,
ValueMapTypeRemapper *TypeMapper) {
assert(NameSuffix && "NameSuffix cannot be null!");
#ifndef NDEBUG
for (Function::const_arg_iterator I = OldFunc->arg_begin(),
E = OldFunc->arg_end(); I != E; ++I)
assert(VMap.count(I) && "No mapping from source argument specified!");
// scan the parameters of the old and new functions. Unused and/or
// non-byval parameters should have the same type and alignment. Used
// byval parameters from the old function must be the first argument
// of structure type that is the type of the coresponding argument in
// the new function.
{
int i = 1;
Function::const_arg_iterator Io = OldFunc->arg_begin();
Function::const_arg_iterator Eo = OldFunc->arg_end();
Function::arg_iterator In = NewFunc->arg_begin(), En = NewFunc->arg_end();
while((Io != Eo) && (In != En)) {
// verify that argument byval attributes match:
assert((Io->hasByValAttr() == In->hasByValAttr()) &&
"old/new function parameter byval attribute mismatch!");
// The use_empty attributes of all the new function parameters
// must be set, since the function at present should not
// contain any code.
assert((In->use_empty()) &&
"new function parameter not use_empty?");
// verify that the VMap maps the parameter of the old function to
// those of the new function in listed order.
assert((VMap[Io] == In) &&
"Unexpected mapping between params of old and new fcns.");
if (!Io->hasByValAttr() || Io->use_empty()) {
// verify that arguments without byval are of same type and
// alignment.
assert((Io->getType() == In->getType()) &&
"non byval or use_empty type mismatch");
assert((OldFunc->getParamAlignment(i) == NewFunc->getParamAlignment(i))
&& "non byval or use_empty alignment mismatch");
} else /* Io->hasByValAttr() && !Io->use_empty() */ {
assert((Io->getType() != In->getType()) &&
"types of used byval arguments matches!");
PointerType *oldTypePtr = dyn_cast<PointerType>(Io->getType());
assert((oldTypePtr != NULL) &&
"old used byval argument type not PointerType!");
PointerType *newTypePtr = dyn_cast<PointerType>(In->getType());
assert((newTypePtr != NULL) &&
"new used byval argument type not PointerType!");
StructType * newStructType =
dyn_cast<StructType>(newTypePtr->getElementType());
assert((newStructType != NULL) &&
"new used byval argument not ptr to StructType!");
assert((newStructType->getNumElements() == 3) &&
"new used byval argument struct type doesn't have 3 fields!");
assert((newStructType->getElementType(0) ==
oldTypePtr->getElementType()) &&
"new used byval arg struct first field != old byval tgt type.");
}
++Io;
++In;
++i;
}
}
#endif
// Loop over all the used byval arguments in the old function. For
// each such argument,
//
// 0) If we haven't created it already, create a basic block for the
// new function.
//
// 1) find the associated byval argument of the new function,
// we do this by simply looking it up in VMap[].
//
// 2) construct a GEP instruction that computes a pointer
// to the copy of the byval argument in the old function
// that resides in the structure pointed to by the associated
// argument in the new function, and stores this value in a
// SSA virtual register.
//
// In passing, insert the GEP instruction into the new
// basic block we inserted in the new function.
//
// 3) Modify the VMap, so that it associates the byval parameter in
// old function with the new SSA register. Note that on entry
// VMap associates the byval parameter in the old function with
// the corresponding parameter in the new function.
BasicBlock * header_blk = NULL;
BasicBlock * first_cloned_blk = NULL;
{
Function::const_arg_iterator Io = OldFunc->arg_begin();
Function::const_arg_iterator Eo = OldFunc->arg_end();
Function::arg_iterator In = NewFunc->arg_begin(), En = NewFunc->arg_end();
while((Io != Eo) && (In != En)) {
if (Io->hasByValAttr() && !Io->use_empty()) {
// construct a basic block for the new function if we haven't
// done so already.
if ( header_blk == NULL ) {
header_blk = BasicBlock::Create(NewFunc->getContext(), "header",
NewFunc);
IRBuilder<> builder(header_blk);
}
Value *Idx[2];
Idx[0] = ConstantInt::get(Type::getInt32Ty(NewFunc->getContext()), 0);
Idx[1] = ConstantInt::get(Type::getInt32Ty(NewFunc->getContext()), 0);
GetElementPtrInst * gep_inst =
GetElementPtrInst::Create(VMap[Io], Idx,
(VMap[Io])->getName() + ".cooked", header_blk);
VMap[Io] = gep_inst;
}
++Io;
++In;
}
}
// Loop over all of the basic blocks in the function, cloning them as
// appropriate. Note that we save BE this way in order to handle cloning of
// recursive functions into themselves.
//
for (Function::const_iterator BI = OldFunc->begin(), BE = OldFunc->end();
BI != BE; ++BI) {
const BasicBlock &BB = *BI;
// Create a new basic block and copy instructions into it!
BasicBlock *CBB = CloneBasicBlock(&BB, VMap, NameSuffix, NewFunc, CodeInfo);
// Make note of the first cloned basic block
if ( first_cloned_blk == NULL ) {
first_cloned_blk = CBB;
}
// Add basic block mapping.
VMap[&BB] = CBB;
// It is only legal to clone a function if a block address within that
// function is never referenced outside of the function. Given that, we
// want to map block addresses from the old function to block addresses in
// the clone. (This is different from the generic ValueMapper
// implementation, which generates an invalid blockaddress when
// cloning a function.)
if (BB.hasAddressTaken()) {
Constant *OldBBAddr = BlockAddress::get(const_cast<Function*>(OldFunc),
const_cast<BasicBlock*>(&BB));
VMap[OldBBAddr] = BlockAddress::get(NewFunc, CBB);
}
// Note return instructions for the caller.
if (ReturnInst *RI = dyn_cast<ReturnInst>(CBB->getTerminator()))
Returns.push_back(RI);
}
// Loop over all of the instructions in the function, fixing up operand
// references as we go. This uses VMap to do all the hard work.
for (Function::iterator BB = cast<BasicBlock>(VMap[OldFunc->begin()]),
BE = NewFunc->end(); BB != BE; ++BB)
// Loop over all instructions, fixing each one as we find it...
for (BasicBlock::iterator II = BB->begin(); II != BB->end(); ++II)
RemapInstruction(II, VMap,
ModuleLevelChanges ? RF_None : RF_NoModuleLevelChanges,
TypeMapper);
// Assuming it exists, add an unconditional branch from the end of the
// header block to the first block cloned over from the old function.
if ( header_blk != NULL ) {
assert((first_cloned_blk != NULL) && "First cloned block is NULL?!?");
BranchInst::Create(first_cloned_blk, header_blk);
}
return;
}
//
// Function: cloneFunction()
//
// Description:
// It clones a function when dealing with byval argments for baggy bounds
// checking. The cloned function pads and aligns the byvalue arguments in
// the original function. After cloned, the original function calls this
// cloned function, so that externel code and indirect calls use the original
// to call the cloned function.
//
Function *
InsertBaggyBoundsChecks::cloneFunction (Function * F) {
Type *Int8Type = Type::getInt8Ty(F->getContext());
Value *zero = ConstantInt::get(Type::getInt32Ty(F->getContext()), 0);
Value *Idx[] = { zero, zero };
// Get the function type.
FunctionType *FTy = F->getFunctionType();
// Vector to store all arguments' types.
std::vector<Type*> TP;
// Vector to store new types for byval arguments
std::vector<Type*> NTP;
// Vector to store the alignment size of new padded types.
std::vector<unsigned int> LEN;
unsigned int i = 0;
//
// Loop over all the arguments of the function. If one argument has the byval
// attribute, it will be padded and push into the vector; If it does not have
// the byval attribute, it will be pushed into the vector without any change.
// Then all the types in vector will be used to create the clone function.
//
for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end();
I != E; ++I, ++i) {
// Deal with the argument that without byval attribute
if (!I->hasByValAttr()) {
TP.push_back(FTy->getParamType(i));
continue;
}
// Deal with the argument that with byval attribute, but without use.
if(I->use_empty()) {
TP.push_back(FTy->getParamType(i));
continue;
}
//
// Find the greatest power-of-two size that is larger than the argument's
// current size with metadata's size.
//
assert (isa<PointerType>(I->getType()));
Type * ET = cast<PointerType>(I->getType())->getElementType();
unsigned long AllocSize = TD->getTypeAllocSize(ET);
unsigned long adjustedSize = AllocSize + sizeof(BBMetaData);
unsigned int size = findP2Size (adjustedSize);
// Get the alignment size and push it into the vector.
unsigned int alignment = 1u << size;
LEN.push_back(alignment);
//
// Create a structure type to pad the argument. The first element will
// be the argument's type; the second will be an array of bytes that
// will pad the size out; the third will be the metadata type.
//
Type *newType1 = ArrayType::get(Int8Type, alignment - adjustedSize);
Type *metadataType = TypeBuilder<BBMetaData, false>::get(I->getContext());
StructType *newType = StructType::get(ET, newType1, metadataType, NULL);
// push the padded type into the vectors
TP.push_back(newType->getPointerTo());
NTP.push_back(newType);
}//end for arguments handling
// Create the new function. Return type is same as that of original
// instruction.
// Setup NewF with non-byval arguments as per F, and byval arguments
// of type padded out to a power of two.
FunctionType *NewFTy = FunctionType::get(FTy->getReturnType(), TP, false);
Function *NewF = Function::Create(NewFTy,
GlobalValue::InternalLinkage,
F->getName() + ".TEST",
F->getParent());
// iterate through the parameter list, and set the alignment of all
// byval arguments.
{
std::vector<unsigned int>::iterator it = LEN.begin();
i = 1;
for (Function::arg_iterator Io = F->arg_begin(), Eo = F->arg_end(),
In = NewF->arg_begin(), En = NewF->arg_end();
(Io != Eo) && (In != En);
++Io, ++In, ++i) {
// set argument names
In->setName(Io->getName());
// skip arguments without byval attribute or use.
if (!Io->hasByValAttr() || Io->use_empty()) continue;
{
AttrBuilder AB0;
AB0.addAttribute(Attribute::ByVal);
In->addAttr(AttributeSet::get(NewF->getContext(), 0, AB0));
AttrBuilder AB1;
AB1.addAlignmentAttr (*it);
In->addAttr(AttributeSet::get(In->getContext(), 0, AB1));
++it;
}
}
}
//
// Create the arguments mapping between the original and the clonal function
// to prepare for cloning the whole function.
//
ValueToValueMapTy VMap;
Function::arg_iterator DestI = NewF->arg_begin();
for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end();
I != E; ++I) {
DestI->setName(I->getName());
VMap[I] = DestI++;
}
// Perform the cloning.
SmallVector<ReturnInst*, 8> Returns;
cloneFunctionInto(NewF, F, VMap, false, Returns);
//
// Since externel code and indirect call use the original function
// So we make the original function to call the clone function.
// First delete the body of the function and creat a block in it.
//
F->dropAllReferences();
BasicBlock * BB = BasicBlock::Create(F->getContext(), "clone", F, 0);
//
// Create an STL container with the arguments to call the clone function.
std::vector<Value *> args;
//
// Look over all arguments. If the argument has byval attribute,
// alloca its padded new type, store the argument's value into
// it, and push the allocated type into the vector. If the
// argument has no such attribute, just push it into the vector.
//
// Iterator to get the new types stores in the vector.
std::vector<Type*>::iterator iter = NTP.begin();
for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end();
I != E; ++I) {
if (!I->hasByValAttr()) { // add "|| I->use_empty()" here?
args.push_back(I);
continue;
}
Type* newType = *iter++;
AllocaInst *AINew = new AllocaInst(newType, "", BB);
LoadInst *LINew = new LoadInst(I, "", BB);
GetElementPtrInst *GEPNew = GetElementPtrInst::Create(AINew,
Idx,
Twine(""),
BB);
new StoreInst(LINew, GEPNew, BB);
args.push_back(AINew);
}
//
// Use the arguments in the vector to call the cloned function.
//
// If F is not void, return the return value of NewF. Otherwise,
// just return.
//
CallInst * call_to_new_func = CallInst::Create(NewF, args, "", BB);
if ( F->getReturnType() == Type::getVoidTy(F->getContext())) {
ReturnInst::Create(F->getContext(), BB);
} else {
ReturnInst::Create(F->getContext(), call_to_new_func, BB);
}
return NewF;
}
//
// Function: callClonedFunction()
//
// Description:
// It changes all the uses for the original function with byval arguments
// A direct call to the orignal function is replaced with a call to the
// cloned function.
//
void
InsertBaggyBoundsChecks::callClonedFunction (Function * F, Function * NewF) {
Type *Int8Type = Type::getInt8Ty(F->getContext());
// Vector to store the alignment size of new padded types.
std::vector<unsigned int> LEN;
//
//Change uses so that the direct calls to the original function become direct
// calls to the cloned function.
//
for (Value::use_iterator FU = F->use_begin(), FE = F->use_end();
FU != FE; ++FU) {
if (CallInst * CI = dyn_cast<CallInst>(*FU)) {
if (CI->getCalledFunction() == F) {
Function *Caller = CI->getParent()->getParent();
Instruction *InsertPoint;
BasicBlock::iterator insrt = Caller->front().begin();
for (; isa<AllocaInst>(InsertPoint = insrt); ++insrt) {;}
//
// Create an STL container with the arguments to call the cloned
// function.
//
std::vector<Value *> args;
unsigned int i = 0;
// Look over all arguments. If the argument has byval attribute,
// alloca its padded new type, store the argument's value into it.
// and push the allocated type into the vector. If the argument
// has no such attribute, just push it into the vector.
//
for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end();
I != E; ++I, ++i) {
if (!I->hasByValAttr() || I->use_empty()) {
args.push_back(I);
continue;
}
assert (isa<PointerType>(I->getType()));
Type * ET = cast<PointerType>(I->getType())->getElementType();
unsigned long AllocSize = TD->getTypeAllocSize(ET);
unsigned long adjustedSize = AllocSize + sizeof(BBMetaData);
unsigned int size = findP2Size (adjustedSize);
// Get the alignment size and push it into the vector.
unsigned int alignment = 1u << size;
LEN.push_back(alignment);
// Create a structure type to pad the argument. The first element
// will be the argument's type; the second will be an array of
// bytes that will pad the size out; the third will be the metadata
// type.
//
Type *newType1 = ArrayType::get(Int8Type, alignment - adjustedSize);
Type *meteTP = TypeBuilder<BBMetaData, false>::get(I->getContext());
StructType *newType = StructType::get(ET,
newType1,
meteTP,
NULL);
Value *zero = ConstantInt::get(Type::getInt32Ty(F->getContext()),0);
Value *Idx[] = { zero, zero };
AllocaInst *AINew = new AllocaInst(newType, 0, alignment, "", InsertPoint);
LoadInst *LINew = new LoadInst(CI->getOperand(i), "", CI);
GetElementPtrInst *GEPNew = GetElementPtrInst::Create(AINew,
Idx,
Twine(""),
CI);
new StoreInst(LINew, GEPNew, CI);
args.push_back(AINew);
}
// replace the original function with the cloned one.
CallInst *CallI = CallInst::Create(NewF, args,"", CI);
// Add alignment attribute when calling the cloned function.
std::vector<unsigned int>::iterator iiter = LEN.begin();
i = 0;
for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end();
I != E; ++I, ++i) {
if (I->hasByValAttr() && !I->use_empty()) {
#if 0
// Remove the old alignment attribute
CallI->removeAttribute(i + 1, Attributes(Attribute::Alignment));
#endif
// Add the new alignment attribute
AttrBuilder AB;
AB.addAlignmentAttr (*iiter++);
AttributeSet AS = CallI->getAttributes();
AS = AS.addAttributes(F->getContext(), i + 1,
AttributeSet::get(F->getContext(), 0, AB));
CallI->setAttributes(AS);
}
}
CallI->setCallingConv(CI->getCallingConv());
CI->replaceAllUsesWith(CallI);
CI->eraseFromParent();
}
}
} // end for use changes
return;
}
//
// 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 results
TD = &getAnalysis<DataLayout>();
//
// Align and pad global variables.
//
std::vector<GlobalVariable *> varsToTransform;
Module::global_iterator GI = M.global_begin(), GE = M.global_end();
for (; GI != GE; ++GI) {
if (GlobalVariable * GV = mustAdjustGlobalValue (GI))
varsToTransform.push_back (GV);
}
for (unsigned index = 0; index < varsToTransform.size(); ++index) {
adjustGlobalValue (varsToTransform[index]);
}
varsToTransform.clear();
//
// Align and pad stack allocations (allocas) that are registered with the
// run-time. We don't do all stack objects because we don't need to adjust
// the size of an object that is never returned in a table lookup.
//
adjustAllocasFor (M.getFunction ("pool_register_stack"));
adjustAllocasFor (M.getFunction ("pool_register_stack_debug"));
// changes for register argv
adjustArgv(M.getFunction ("poolargvregister"));
// Deal with byval argument.
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++ I) {
Function *F = I;
if (!mustCloneFunction(F)) continue;
#if 0
Function *NewF = cloneFunction(F);
callClonedFunction(F, NewF);
#else
cloneFunction(F);
#endif
}
return true;
}
}