blob: 838b37b33aa59698ab7cca39e636ce9ec0e30145 [file] [log] [blame]
//===- InstrumentMemoryAccesses.cpp - Insert load/store checks ------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass instruments loads, stores, and other memory intrinsics with
// load/store checks by inserting the relevant __loadcheck and/or
// __storecheck calls before the them.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "instrument-memory-accesses"
#include "CommonMemorySafetyPasses.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Pass.h"
#include "llvm/InstVisitor.h"
#include "llvm/Transforms/Instrumentation.h"
using namespace llvm;
STATISTIC(LoadsInstrumented, "Loads instrumented");
STATISTIC(StoresInstrumented, "Stores instrumented");
STATISTIC(AtomicsInstrumented, "Atomic memory intrinsics instrumented");
STATISTIC(IntrinsicsInstrumented, "Block memory intrinsics instrumented");
namespace {
class InstrumentMemoryAccesses : public FunctionPass,
public InstVisitor<InstrumentMemoryAccesses> {
const DataLayout *TD;
IRBuilder<> *Builder;
PointerType *VoidPtrTy;
IntegerType *SizeTy;
Function *LoadCheckFunction;
Function *StoreCheckFunction;
void instrument(Value *Pointer, Value *AccessSize, Function *Check,
Instruction &I);
public:
static char ID;
InstrumentMemoryAccesses(): FunctionPass(ID) { }
virtual bool doInitialization(Module &M);
virtual bool runOnFunction(Function &F);
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<DataLayout>();
AU.setPreservesCFG();
}
virtual const char *getPassName() const {
return "InstrumentMemoryAccesses";
}
// Visitor methods
void visitLoadInst(LoadInst &LI);
void visitStoreInst(StoreInst &SI);
void visitAtomicCmpXchgInst(AtomicCmpXchgInst &I);
void visitAtomicRMWInst(AtomicRMWInst &I);
void visitMemIntrinsic(MemIntrinsic &MI);
};
} // end anon namespace
char InstrumentMemoryAccesses::ID = 0;
INITIALIZE_PASS(InstrumentMemoryAccesses, "instrument-memory-accesses",
"Instrument memory accesses", false, false)
FunctionPass *llvm::createInstrumentMemoryAccessesPass() {
return new InstrumentMemoryAccesses();
}
bool InstrumentMemoryAccesses::doInitialization(Module &M) {
Type *VoidTy = Type::getVoidTy(M.getContext());
VoidPtrTy = Type::getInt8PtrTy(M.getContext());
SizeTy = IntegerType::getInt64Ty(M.getContext());
// Create function prototypes
M.getOrInsertFunction("__loadcheck", VoidTy, VoidPtrTy, SizeTy, NULL);
M.getOrInsertFunction("__storecheck", VoidTy, VoidPtrTy, SizeTy, NULL);
return true;
}
bool InstrumentMemoryAccesses::runOnFunction(Function &F) {
// Check that the load and store check functions are declared.
LoadCheckFunction = F.getParent()->getFunction("__loadcheck");
assert(LoadCheckFunction && "__loadcheck function has disappeared!\n");
StoreCheckFunction = F.getParent()->getFunction("__storecheck");
assert(StoreCheckFunction && "__storecheck function has disappeared!\n");
TD = &getAnalysis<DataLayout>();
IRBuilder<> TheBuilder(F.getContext());
Builder = &TheBuilder;
// Visit all of the instructions in the function.
visit(F);
return true;
}
void InstrumentMemoryAccesses::instrument(Value *Pointer, Value *AccessSize,
Function *Check, Instruction &I) {
Builder->SetInsertPoint(&I);
Value *VoidPointer = Builder->CreatePointerCast(Pointer, VoidPtrTy);
CallInst *CI = Builder->CreateCall2(Check, VoidPointer, AccessSize);
// Copy debug information if it is present.
if (MDNode *MD = I.getMetadata("dbg"))
CI->setMetadata("dbg", MD);
}
void InstrumentMemoryAccesses::visitLoadInst(LoadInst &LI) {
// Instrument a load instruction with a load check.
Value *AccessSize = ConstantInt::get(SizeTy,
TD->getTypeStoreSize(LI.getType()));
instrument(LI.getPointerOperand(), AccessSize, LoadCheckFunction, LI);
++LoadsInstrumented;
}
void InstrumentMemoryAccesses::visitStoreInst(StoreInst &SI) {
// Instrument a store instruction with a store check.
uint64_t Bytes = TD->getTypeStoreSize(SI.getValueOperand()->getType());
Value *AccessSize = ConstantInt::get(SizeTy, Bytes);
instrument(SI.getPointerOperand(), AccessSize, StoreCheckFunction, SI);
++StoresInstrumented;
}
void InstrumentMemoryAccesses::visitAtomicRMWInst(AtomicRMWInst &I) {
// Instrument an AtomicRMW instruction with a store check.
Value *AccessSize = ConstantInt::get(SizeTy,
TD->getTypeStoreSize(I.getType()));
instrument(I.getPointerOperand(), AccessSize, StoreCheckFunction, I);
++AtomicsInstrumented;
}
void InstrumentMemoryAccesses::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
// Instrument an AtomicCmpXchg instruction with a store check.
Value *AccessSize = ConstantInt::get(SizeTy,
TD->getTypeStoreSize(I.getType()));
instrument(I.getPointerOperand(), AccessSize, StoreCheckFunction, I);
++AtomicsInstrumented;
}
void InstrumentMemoryAccesses::visitMemIntrinsic(MemIntrinsic &MI) {
// Instrument llvm.mem[set|cpy|move].* calls with load/store checks.
Builder->SetInsertPoint(&MI);
Value *AccessSize = Builder->CreateIntCast(MI.getLength(), SizeTy,
/*isSigned=*/false);
// memcpy and memmove have a source memory area but memset doesn't
if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(&MI))
instrument(MTI->getSource(), AccessSize, LoadCheckFunction, MI);
instrument(MI.getDest(), AccessSize, StoreCheckFunction, MI);
++IntrinsicsInstrumented;
}