blob: dfd7a4d599ef4b2698f95a04de521571d5f5b75c [file] [log] [blame]
//===- DebugInstrumentation.cpp - Modify run-time checks to track debug info -//
//
// The LLVM Compiler Infrastructure
//
// 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 modifies calls to the pool allocator and SAFECode run-times to
// track source level debugging information.
//
// Notes:
// Some of this code is based off of code from the getLocationInfo() method in
// LLVM.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "debug-instrumentation"
#include "llvm/Analysis/DebugInfo.h"
#include "llvm/Constants.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Instructions.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Metadata.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InstIterator.h"
#include "llvm/ADT/VectorExtras.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/GetElementPtrTypeIterator.h"
#include "safecode/DebugInstrumentation.h"
#include "safecode/Utility.h"
#include <cstdlib>
#include <vector>
using namespace llvm;
namespace llvm {
char DebugInstrument::ID = 0;
// Register the pass
static
RegisterPass<DebugInstrument> X ("debuginstrument",
"Add Debug Data to SAFECode Run-Time Checks");
static int tagCounter = 0;
//
// Basic LLVM Types
//
static Type * VoidType = 0;
static Type * Int8Type = 0;
static Type * Int32Type = 0;
///////////////////////////////////////////////////////////////////////////
// Command line options
///////////////////////////////////////////////////////////////////////////
namespace {
///////////////////////////////////////////////////////////////////////////
// Pass Statistics
///////////////////////////////////////////////////////////////////////////
STATISTIC (FoundSrcInfo, "Number of Source Information Locations Found");
STATISTIC (QueriedSrcInfo, "Number of Source Information Locations Queried");
}
///////////////////////////////////////////////////////////////////////////
// Static Functions
///////////////////////////////////////////////////////////////////////////
//
// Function: copyToDefaultSection()
//
// Description:
// This function examines the specified LLVM value and determines if it is
// a GEP into a global value in a special section. If it is, it makes a copy
// of the global in the default section and returns a pointer to it.
//
// Inputs:
// V - The value to process.
//
// Return value:
// Either V is returned or a pointer to a new GlobalVariable in the default
// section is returned.
//
static inline Value *
copyToDefaultSection (Value * V) {
if (ConstantExpr * GEP = dyn_cast<ConstantExpr>(V)) {
if (GlobalVariable * GV = dyn_cast<GlobalVariable>(GEP->getOperand(0))) {
if (GV->hasSection()) {
//
// Get the module in which this value belongs.
//
Module * M = GV->getParent();
//
// Get the element type of the global variable.
//
Type * Ty = GV->getType()->getElementType();
GlobalVariable * SrcGV = new GlobalVariable (*M,
Ty,
GV->isConstant(),
GV->getLinkage(),
GV->getInitializer(),
GV->getName(),
0,
GV->isThreadLocal(),
0);
SrcGV->copyAttributesFrom (GV);
SrcGV->setSection ("");
return SrcGV;
}
}
}
return V;
}
///////////////////////////////////////////////////////////////////////////
// Class Methods
///////////////////////////////////////////////////////////////////////////
GetSourceInfo::~GetSourceInfo() {}
//
// Method: operator()
//
// Description:
// Return the source information associated with the call instruction by
// finding the location within the source code in which the call is made.
//
// Inputs:
// CI - The call instruction
//
// Return value:
// A pair of LLVM values. The first is the source file name; the second is
// the line number. Default values are given if no source line information
// can be found.
//
std::pair<Value *, Value *>
LocationSourceInfo::operator() (CallInst * CI) {
static int count=0;
//
// Update the number of source locations queried.
//
++QueriedSrcInfo;
//
// Create default debugging values in case we don't find any debug
// information. The filename becomes the function name (if the function
// has a name) and the line number becomes a unique identifier.
//
std::string filename = "<unknown>";
unsigned int lineno = ++count;
if (CI->getParent()->getParent()->hasName())
filename = CI->getParent()->getParent()->getName();
//
// Get the line number and source file information for the call if it exists.
//
if (MDNode *Dbg = CI->getMetadata(dbgKind)) {
DILocation Loc (Dbg);
filename = Loc.getDirectory().str() + "/" + Loc.getFilename().str();
lineno = Loc.getLineNumber();
++FoundSrcInfo;
}
//
// Convert the source filename and line number information into LLVM values.
//
Value * LineNumber = ConstantInt::get (Int32Type, lineno);
Value * SourceFile;
if (SourceFileMap.find (filename) != SourceFileMap.end()) {
SourceFile = SourceFileMap[filename];
} else {
Constant * FInit = ConstantArray::get (CI->getContext(), filename);
Module * M = CI->getParent()->getParent()->getParent();
SourceFile = new GlobalVariable (*M,
FInit->getType(),
true,
GlobalValue::InternalLinkage,
FInit,
"sourcefile");
SourceFileMap[filename] = SourceFile;
}
return std::make_pair (SourceFile, LineNumber);
}
//
// Method: operator()
//
// Description:
// Return the source information associated with a value within the call
// instruction. This is mainly intended to provide better source file
// information to poolregister() calls.
//
// Inputs:
// CI - The call instruction
//
// Return value:
// A pair of LLVM values. The first is the source file name; the second is
// the line number. Default values are given if no source line information
// can be found.
//
std::pair<Value *, Value *>
VariableSourceInfo::operator() (CallInst * CI) {
assert (((CI->getNumOperands()) > 2) &&
"Not enough information to get debug info!\n");
Value * LineNumber;
Value * SourceFile;
//
// Create a default line number and source file information for the call.
//
LineNumber = ConstantInt::get (Int32Type, 0);
std::string filename = "<unknown>";
Module * M = CI->getParent()->getParent()->getParent();
//
// Get the value for which we want debug information.
//
Value * V = CI->getOperand(2)->stripPointerCasts();
//
// Try to get information about where in the program the value was allocated.
//
if (GlobalVariable * GV = dyn_cast<GlobalVariable>(V)) {
NamedMDNode *NMD = M->getNamedMetadata("llvm.dbg.gv");
if (NMD) {
for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) {
DIDescriptor DIG(cast<MDNode>(NMD->getOperand(i)));
if (!DIG.isGlobalVariable())
continue;
if (DIGlobalVariable(NMD->getOperand(i)).getGlobal() == GV) {
DIGlobalVariable Var(NMD->getOperand(i));
LineNumber = ConstantInt::get (Int32Type, Var.getLineNumber());
filename = Var.getCompileUnit().getDirectory().str() + "/" + Var.getCompileUnit().getFilename().str();
}
}
}
} else {
if (Instruction *I = dyn_cast<Instruction>(V))
if (MDNode *Dbg = I->getMetadata(dbgKind)) {
DILocation Loc (Dbg);
filename = Loc.getDirectory().str() + "/" + Loc.getFilename().str();
LineNumber = ConstantInt::get (Int32Type, Loc.getLineNumber());
}
}
if (SourceFileMap.find (filename) != SourceFileMap.end()) {
SourceFile = SourceFileMap[filename];
} else {
Constant * FInit = ConstantArray::get (CI->getContext(), filename);
Module * M = CI->getParent()->getParent()->getParent();
SourceFile = new GlobalVariable (*M,
FInit->getType(),
true,
GlobalValue::InternalLinkage,
FInit,
"sourcefile");
SourceFileMap[filename] = SourceFile;
}
return std::make_pair (SourceFile, LineNumber);
}
//
// Method: processFunction()
//
// Description:
// Process each function in the module.
//
// Inputs:
// F - The function to transform into a debug version. This *can be NULL.
//
void
DebugInstrument::transformFunction (Function * F, GetSourceInfo & SI) {
// If the function does not exist within the module, it does not need to
// be transformed.
if (!F) return;
//
// Create the function prototype for the debug version of the function. This
// function will have an identical type to the original *except* that it will
// have additional debug parameters at the end.
//
const FunctionType * FuncType = F->getFunctionType();
std::vector<Type *> ParamTypes (FuncType->param_begin(),
FuncType->param_end());
//
// See note on vararg functions below.
//
if (!F->isVarArg())
{
ParamTypes.push_back (Int32Type);
ParamTypes.push_back (VoidPtrTy);
ParamTypes.push_back (Int32Type);
}
//
// Check to see if the debug version of the function already exists.
//
bool hadToCreateFunction = true;
if (F->getParent()->getFunction(F->getName().str() + "_debug"))
hadToCreateFunction = false;
//
// Create the expected type of the debug version. Note: For functions that
// take a variable number of arguments, this is set up so that the debugging
// information will be pushed back at the end of the variable argument list.
//
FunctionType * DebugFuncType = FunctionType::get (FuncType->getReturnType(),
ParamTypes,
F->isVarArg());
std::string funcdebugname = F->getName().str() + "_debug";
Constant * FDebug = F->getParent()->getOrInsertFunction (funcdebugname,
DebugFuncType);
#if 0
//
// Give the function a body. This is used for ensuring that SAFECode plays
// nicely with LLVM's bugpoint tool. By having a body, the program will link
// correctly even when the intrinsic renaming pass is removed by bugpoint.
//
if (hadToCreateFunction) {
Function * DebugFunc = dyn_cast<Function>(FDebug);
assert (DebugFunc);
LLVMContext & Context = F->getContext();
BasicBlock * entryBB=BasicBlock::Create (Context, "entry", DebugFunc);
Type * VoidTy = Type::getVoidTy(Context);
if (DebugFunc->getReturnType() == VoidTy) {
ReturnInst::Create (Context, entryBB);
} else {
Value * retValue = UndefValue::get (DebugFunc->getReturnType());
ReturnInst::Create (Context, retValue, entryBB);
}
}
#endif
//
// Create a set of call instructions that must be modified.
//
std::vector<CallInst *> Worklist;
Function::use_iterator i, e;
for (i = F->use_begin(), e = F->use_end(); i != e; ++i) {
if (CallInst * CI = dyn_cast<CallInst>(*i)) {
Worklist.push_back (CI);
}
}
//
// Process all call instructions in the worklist.
//
for (unsigned index = 0; index < Worklist.size(); ++index) {
//
// Get a call instruction off of the work list.
//
CallInst * CI = Worklist[index];
CallSite CS (CI);
//
// Get the line number and source file information for the call.
//
Value * LineNumber;
Value * SourceFile;
std::pair<Value *, Value *> Info = SI (CI);
SourceFile = Info.first;
LineNumber = Info.second;
//
// If the source filename is in the meta-data section, make a copy of it in
// the default section. This ensures that it gets code generated.
//
SourceFile = copyToDefaultSection (SourceFile);
//
// Transform the function call.
//
std::vector<Value *> args;
args.insert (args.end(), CS.arg_begin(), CS.arg_end());
args.push_back (ConstantInt::get(Int32Type, tagCounter++));
args.push_back (castTo (SourceFile, VoidPtrTy, "", CI));
args.push_back (LineNumber);
CallInst * NewCall = CallInst::Create (FDebug,
args,
CI->getName(),
CI);
CI->replaceAllUsesWith (NewCall);
CI->eraseFromParent();
}
return;
}
//
// Method: runOnModule()
//
// Description:
// This is where the pass begin execution.
//
// Return value:
// true - The module was modified.
// false - The module was left unmodified.
//
bool
DebugInstrument::runOnModule (Module &M) {
// Create the void pointer type
VoidPtrTy = getVoidPtrType(M);
//
// Create needed LLVM types.
//
VoidType = Type::getVoidTy(M.getContext());
Int8Type = IntegerType::getInt8Ty(M.getContext());
Int32Type = IntegerType::getInt32Ty(M.getContext());
//
// Get the ID number for debug metadata.
//
unsigned dbgKind = M.getContext().getMDKindID("dbg");
//
// Transform allocations, load/store checks, and bounds checks.
//
LocationSourceInfo LInfo (dbgKind);
VariableSourceInfo VInfo (dbgKind);
// Allocation, check, and registration functions
transformFunction (M.getFunction ("poolalloc"), LInfo);
transformFunction (M.getFunction ("poolcalloc"), LInfo);
transformFunction (M.getFunction ("poolrealloc"), LInfo);
transformFunction (M.getFunction ("poolstrdup"), LInfo);
transformFunction (M.getFunction ("poolfree"), LInfo);
transformFunction (M.getFunction ("poolcheck"), LInfo);
transformFunction (M.getFunction ("poolcheckui"), LInfo);
transformFunction (M.getFunction ("poolcheckalign"), LInfo);
transformFunction (M.getFunction ("poolcheckalignui"), LInfo);
transformFunction (M.getFunction ("boundscheck"), LInfo);
transformFunction (M.getFunction ("boundscheckui"), LInfo);
transformFunction (M.getFunction ("exactcheck2"), LInfo);
transformFunction (M.getFunction ("fastlscheck"), LInfo);
transformFunction (M.getFunction ("funccheck"), LInfo);
transformFunction (M.getFunction ("funccheckui"), LInfo);
transformFunction (M.getFunction ("pool_register"), LInfo);
transformFunction (M.getFunction ("pool_register_stack"), LInfo);
transformFunction (M.getFunction ("pool_unregister"), LInfo);
transformFunction (M.getFunction ("pool_unregister_stack"), LInfo);
// Format string function intrinsic
transformFunction (M.getFunction ("__sc_fscallinfo"), LInfo);
// Standard C library wrappers
transformFunction (M.getFunction ("pool_memccpy"), LInfo);
transformFunction (M.getFunction ("pool_memchr"), LInfo);
transformFunction (M.getFunction ("pool_memcmp"), LInfo);
transformFunction (M.getFunction ("pool_memcpy"), LInfo);
transformFunction (M.getFunction ("pool_memmove"), LInfo);
transformFunction (M.getFunction ("pool_memset"), LInfo);
transformFunction (M.getFunction ("pool_strcat"), LInfo);
transformFunction (M.getFunction ("pool_strchr"), LInfo);
transformFunction (M.getFunction ("pool_strcmp"), LInfo);
transformFunction (M.getFunction ("pool_strcoll"), LInfo);
transformFunction (M.getFunction ("pool_strcpy"), LInfo);
transformFunction (M.getFunction ("pool_strcspn"), LInfo);
transformFunction (M.getFunction ("pool_strlen"), LInfo);
transformFunction (M.getFunction ("pool_strncat"), LInfo);
transformFunction (M.getFunction ("pool_strncmp"), LInfo);
transformFunction (M.getFunction ("pool_strncpy"), LInfo);
transformFunction (M.getFunction ("pool_strpbrk"), LInfo);
transformFunction (M.getFunction ("pool_strrchr"), LInfo);
transformFunction (M.getFunction ("pool_strspn"), LInfo);
transformFunction (M.getFunction ("pool_strstr"), LInfo);
transformFunction (M.getFunction ("pool_strxfrm"), LInfo);
transformFunction (M.getFunction ("pool_mempcpy"), LInfo);
transformFunction (M.getFunction ("pool_strcasestr"), LInfo);
transformFunction (M.getFunction ("pool_stpcpy"), LInfo);
transformFunction (M.getFunction ("pool_strnlen"), LInfo);
transformFunction (M.getFunction ("pool_bcmp"), LInfo);
transformFunction (M.getFunction ("pool_bcopy"), LInfo);
transformFunction (M.getFunction ("pool_bzero"), LInfo);
transformFunction (M.getFunction ("pool_index"), LInfo);
transformFunction (M.getFunction ("pool_rindex"), LInfo);
transformFunction (M.getFunction ("pool_strcasestr"), LInfo);
transformFunction (M.getFunction ("pool_strcasecmp"), LInfo);
transformFunction (M.getFunction ("pool_strncasecmp"), LInfo);
return true;
}
}