[LLVMdev] How to duplicate a function?
Shawn Kim
shawn.subscribe at gmail.com
Fri Sep 16 11:03:59 PDT 2011
Hi all,
I am a newbie in LLVM and I am trying to replace the function like:
old function || new function
=======================================
int haha(int a) { int haha(int a, char* ID) {
===>
} }
Of course in the newly replaced function "int haha(int, char*ID)", I want to
insert some instrumentation code.
Here is my code that I am working on till now and it generates segmentation
fault in the place I comment with "//////////////////////"
Can you help me? Any advice will be helpful because I am a beginner in llvm.
dulpicateFunction.cpp, test.c, and Make file are attached.
Thank you in advance.
Shawn.
//===- duplicateFunction.cpp - Writing an LLVM Pass
-----------------------===//
//
// The LLVM Compiler Infrastructure
//
//===----------------------------------------------------------------------===//
//
// This file implements the LLVM duplicating function pass.
// It starts by computing a new prototype for the function,
// which is the same as the old function, but has an extra argument.
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/Module.h"
#include "llvm/CallingConv.h"
#include "llvm/DerivedTypes.h"
#include "llvm/InstrTypes.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/BasicBlock.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/CallSite.h"
using namespace llvm;
namespace {
Constant *f;
Function *Fn;
FunctionType *FTy;
Type *RetTy;
std::vector<Type*> Params;
class DP : public FunctionPass {
public:
static char ID;
DP() : FunctionPass(ID) {}
virtual bool doInitialization(Module &M);
virtual bool runOnFunction(Function &F);
virtual bool doFinalization(Module &mdl) {
mdl.dump();
return true;
}
#if 0
// optimization passes should implement the following function to be
efficient.
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
FunctionPass::getAnalysisUsage(AU);
AU.setPreservesAll();
AU.addRequired<AliasAnalysis>();
}
#endif
}; /* class */
}
char DP::ID = 0;
static RegisterPass<DP> IC("duplicateFunction", "Duplicate Function Pass");
bool DP::doInitialization(Module &M) {
// find the function that we want to change.
// f = M.getFunction("haha");
//
Fn = M.getFunction("haha");
// Start by computing a new prototype for the function, which is the
same as
// the old function, but has an extra argument.
FTy = Fn->getFunctionType();
// Find out the return value.
RetTy = FTy->getReturnType();
#if 0
if (Fn->getName() == "haha") {
f = M.getOrInsertFunction("ShawnFunction",
/* return type */ Type::getVoidTy(M.getContext()),
/* actual 1 type */ IntegerType::get(M.getContext(), 32),
NULL);
}
if ( !f ) {
errs() << "### Error: No matched function\n";
}
#endif
#if 0
// f = M.getOrInsertFunction(StringRef Name, FunctionType *T,
AttrListPtr AttributeList);
#endif
// set the calling convention to C.
// so, we interoperate with C Code properly.
// Function *tmp = cast<Function>(f);
// tmp->setCallingConv(CallingConv::C);
Function *tmp = cast<Function>(Fn);
tmp->setCallingConv(CallingConv::C);
return true;
}
bool DP::runOnFunction(Function &F) {
#if 1
Value *param;
// Find the instruction before which you want to insert the function
call
Instruction *nextInstr = F.back().getTerminator();
// Create the actual parameter for the function call
param = ConstantInt::get(Type::getInt32Ty(F.getContext()), 333);
// create and insert the function call
//CallInst::Create(f, param, "", nextInstr);
CallInst::Create(Fn, param, "", nextInstr);
// indicates that we changed the code
//return true;
#endif
Type *NRetTy;
std::vector<Type*> Params(FTy->param_begin(), FTy->param_end());
FunctionType *NFTy = FunctionType::get(FTy->getReturnType(), Params,
false);
// Create the new function body and insert it into the module...
Function *NF = Function::Create(NFTy, Fn->getLinkage());
NF->copyAttributesFrom(Fn);
Fn->getParent()->getFunctionList().insert(Fn, NF);
NF->takeName(Fn);
for (Function::arg_iterator AI=F.arg_begin(), AE=F.arg_end(),
NAI=NF->arg_begin();
AI != AE; ++AI, ++NAI) {
NAI->takeName(AI);
}
// Since we have now create the new function, splice the body of the old
// function right into the new function, leaving the old rotting hulk of
the
// function empty.
NF->getBasicBlockList().splice(NF->begin(), F.getBasicBlockList());
llvm::Value *Globals = --NF->arg_end();
Globals->setName("IOCallIDs");
// Now, exploit all return instructions.
for (Function::iterator BI = NF->begin(), BE = NF->end(); BI != BE;
++BI) {
if (ReturnInst *RI =
llvm::dyn_cast<llvm::ReturnInst>(BI->getTerminator())) {
// Don't support functions that have multiple return values.
assert(RI->getNumOperands() < 2);
// Insert a new load instruction to return.
/////////////////////////////////////////////////////////////////////////////////////
HERE, GENERATE ERROR
/////////////////////////////////////////////////////////////////////////////////////
Value *Load = new llvm::LoadInst(Globals, "globalsret", RI);
/////////////////////////////////////////////////////////////////////////////////////
// Return type is void
if ( RetTy->isVoidTy() ) {
// ReturnInst::Create(Load, 0, RI); // Return void
ReturnInst::Create(F.getContext(), 0, RI); // Return void
RI->getParent()->getInstList().erase(RI);
} else {
// Start with an empty struct.
Value *Return = ConstantAggregateZero::get(NRetTy);
DEBUG(errs() << "Return: " << *Return->getType() << '\n');
// Insert the original return value in field 0
Return = InsertValueInst::Create(Return, RI->getOperand(0),
0, "ret", RI);
DEBUG(errs() << "Return: " << *Return->getType() << '\n');
// Insert the globals return value in field 1
Return = InsertValueInst::Create(Return, Load, 1, "ret",
RI); // <- maybe useless
DEBUG(errs() << "Return: " << *Return->getType() << '\n');
// Update the return instruction
RI->setOperand(0, Return);
}
} // if
} // for
// Replace all uses of the old arguments with the new arguments.
for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(), NI =
NF->arg_begin();
I != E; ++I, ++NI) {
I->replaceAllUsesWith(NI);
}
#if 1
// Replace all callers
while ( !F.use_empty() ) {
CallSite CS(F.use_back());
Instruction *Call = CS.getInstruction();
// Function *CallingF = Call->getParent()->getParent();
// Get the global struct in our caller.
//Value* CallerGlobals = ModifyFunctionRecursive(CallingF).first;
Value* CallerGlobals = NULL; // <- This should be modified later.
// Copy the existing arguments
std::vector<Value*> Args;
Args.reserve(CS.arg_size());
CallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end();
// First, copy regular arguments
for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++AI) {
Args.push_back(*AI);
}
// Then, insert the new argument
Args.push_back(CallerGlobals);
// Lastly, copy any remaining varargs
for (; AI != AE; ++AI) {
Args.push_back(*AI);
}
Instruction *New;
Instruction *Before = Call;
if ( InvokeInst *II = dyn_cast<InvokeInst>(Call) ) {
New = InvokeInst::Create(NF, II->getNormalDest(),
II->getUnwindDest(), Args, "", Before);
cast<InvokeInst>(New)->setCallingConv(CS.getCallingConv());
// cast<InvokeInst>(New)->setParamAttrs(CS.getParamAttrs());
cast<InvokeInst>(New)->setAttributes(CS.getAttributes());
} else {
New = CallInst::Create(NF, Args, "", Before);
cast<CallInst>(New)->setCallingConv(CS.getCallingConv());
// cast<CallInst>(New)->setParamAttrs(CS.getParamAttrs());
cast<CallInst>(New)->setAttributes(CS.getAttributes());
if ( cast<CallInst>(Call)->isTailCall() ) {
cast<CallInst>(New)->setTailCall();
}
}
if (Call->hasName()) {
New->takeName(Call);
} else {
New->setName(NF->getName() + ".ret");
}
Value *GlobalsRet;
if ( Call->getType()->isVoidTy() ) {
// The original function returned nothing, so the new function
returns
// only the globals
GlobalsRet = New;
} else {
// Split the values
Value *OrigRet = ExtractValueInst::Create(New, 0, "origret",
Before);
GlobalsRet = ExtractValueInst::Create(New, 1, "globalsret",
Before);
// Replace all the uses of the original result
Call->replaceAllUsesWith(OrigRet);
}
// Now, store the globals back
new StoreInst(GlobalsRet, CallerGlobals, Before);
DEBUG(errs() << "Call " << *Call << " replaced, function is now " <<
*Call->getParent()->getParent() << "\n");
// Finally, remove the old call from the program, reducing the
use-count of F.
Call->eraseFromParent();
} // while
#endif
return true;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20110916/e302a417/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: duplicateFunction.cpp
Type: text/x-c++src
Size: 9571 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20110916/e302a417/attachment.cpp>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test.c
Type: text/x-csrc
Size: 325 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20110916/e302a417/attachment.c>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test.c
Type: text/x-csrc
Size: 325 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20110916/e302a417/attachment-0001.c>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Makefile
Type: application/octet-stream
Size: 1449 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20110916/e302a417/attachment.obj>
More information about the llvm-dev
mailing list