Hi all,
Sorry for the inconvenient about the previous post. The files were not
attached. So I put them here again.
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.
Thank you in advance.
Shawn.
duplicateFunction.cpp
============================================================================
//===- 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;
}
}; /* 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.
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();
// set the calling convention to C.
// so, we interoperate with C Code properly.
Function *tmp = cast<Function>(Fn);
tmp->setCallingConv(CallingConv::C);
return true;
}
bool DP::runOnFunction(Function &F) {
#if 0
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;
}
test.c
===================================================================================#include
<stdio.h>
#include <stdlib.h>
int v[200];
int haha(int);
int main()
{
int i;
int n=100;
if ( !haha(n) )
exit(-1);
return 1;
}
int haha(int n)
//int haha(int n, char* IOCallIDs)
{
int i;
for (i=1; i<n; i++)
v[i] = v[i-1] + v[i];
printf ("hahaha\n");
return 1;
}
Makefile
===================================================================================LLVM_CONFIG?=llvm-config
# location of the source
# useful if you want separate source and object directories.
SRC_DIR?=$(PWD)
#ifndef VERBOSE
# QUIET:=@
#endif
COMMON_FLAGS=-Wall -Wextra #-fvisibility=hidden
CFLAGS+=$(COMMON_FLAGS) $(shell $(LLVM_CONFIG) --cflags)
CXXFLAGS+=$(COMMON_FLAGS) $(shell $(LLVM_CONFIG) --cxxflags)
#ifeq ($(shell uname),Darwin)
#LOADABLE_MODULE_OPTIONS=-bundle -undefined dynamic_lookup
#else
LOADABLE_MODULE_OPTIONS=-shared -Wl,-O1
#endif
TEST_C=test.c
TEST_FILE=$(subst .c,.s, $(TEST_C))
PLUGIN=duplicateFunction.so
PLUGIN_OBJECTS=duplicateFunction.o
ALL_OBJECTS=$(PLUGIN_OBJECTS)
ALL_TARGETS=$(PLUGIN) $(TEST_FILE)
CPP_OPTIONS+=$(CPPFLAGS) $(shell $(LLVM_CONFIG) --cppflags) -MD -MP
-I$(SRC_DIR)
LD_OPTIONS+=$(LDFLAGS) $(shell $(LLVM_CONFIG) --ldflags)
all: $(ALL_TARGETS)
%.o : $(SRC_DIR)/%.cpp
@echo Compiling $*.cpp
$(QUIET)$(CXX) -c $(CPP_OPTIONS) $(CXXFLAGS) $<
$(PLUGIN): $(PLUGIN_OBJECTS)
@echo Linking $@
$(QUIET)$(CXX) -o $@ $(LOADABLE_MODULE_OPTIONS) $(CXXFLAGS)
$(LD_OPTIONS) $(PLUGIN_OBJECTS)
RUN_FLAGS=-duplicateFunction
$(TEST_FILE): $(TEST_C)
clang -g -O3 -S -emit-llvm $^
# clang -g -O0 -S -emit-llvm $^
# clang -O0 -S -emit-llvm $^
run:
opt -load ./$(PLUGIN) $(RUN_FLAGS) < $(TEST_FILE) > /dev/null 2>
after.s
# opt -load ./$(PLUGIN) $(RUN_FLAGS) < $(TEST_FILE) > /dev/null
clean:
$(QUIET)rm -f $(ALL_OBJECTS) *.d $(PLUGIN) $(TEST_FILE)
-include $(ALL_OBJECTS:.o=.d)
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20110916/15f49b43/attachment.html>
Hi Shawn,
Probably I can answer specifically the question "how to replace old
function call with new one, adding extra char* argument".
Method for gathering information: grep with context for one keyword in
LLVM source and then look for another in results:
find . -name *.cpp -exec grep "CallInst" {} -C 100 \; | less
Results:
1) tools/bugpoint/Miscompilation.cpp gives an example of creating
string array and adding it into call args list starting at line 826:
Constant *InitArray = ConstantArray::get(F->getContext(),
F->getName());
GlobalVariable *funcName
2) Using (1) I implemented my own version here, with more comments:
https://hpcforge.org/scm/viewvc.php/branches/accurate/src/frontend/compile.cpp?revision=476&root=kernelgen&view=markup
I hope it's helpful,
- D.
2011/9/16 Shawn Kim <shawn.subscribe at
gmail.com>:> Hi all,
>
> Sorry for the inconvenient about the previous post. The files were not
> attached. So I put them here again.
>
> 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.
>
>
> Thank you in advance.
> Shawn.
>
>
> duplicateFunction.cpp
>
============================================================================>
> //===- 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;
> }
> }; /* 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.
> 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();
>
> // set the calling convention to C.
> // so, we interoperate with C Code properly.
> Function *tmp = cast<Function>(Fn);
> tmp->setCallingConv(CallingConv::C);
>
> return true;
> }
>
> bool DP::runOnFunction(Function &F) {
> #if 0
> 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;
> }
>
>
> test.c
>
===================================================================================>
#include <stdio.h>
> #include <stdlib.h>
>
> int v[200];
> int haha(int);
>
> int main()
> {
> int i;
> int n=100;
>
> if ( !haha(n) )
> exit(-1);
>
> return 1;
> }
>
> int haha(int n)
> //int haha(int n, char* IOCallIDs)
> {
> int i;
> for (i=1; i<n; i++)
> v[i] = v[i-1] + v[i];
>
> printf ("hahaha\n");
> return 1;
> }
>
> Makefile
>
===================================================================================>
LLVM_CONFIG?=llvm-config
>
> # location of the source
> # useful if you want separate source and object directories.
> SRC_DIR?=$(PWD)
>
> #ifndef VERBOSE
> # QUIET:=@
> #endif
>
> COMMON_FLAGS=-Wall -Wextra #-fvisibility=hidden
> CFLAGS+=$(COMMON_FLAGS) $(shell $(LLVM_CONFIG) --cflags)
> CXXFLAGS+=$(COMMON_FLAGS) $(shell $(LLVM_CONFIG) --cxxflags)
>
> #ifeq ($(shell uname),Darwin)
> #LOADABLE_MODULE_OPTIONS=-bundle -undefined dynamic_lookup
> #else
> LOADABLE_MODULE_OPTIONS=-shared -Wl,-O1
> #endif
>
> TEST_C=test.c
> TEST_FILE=$(subst .c,.s, $(TEST_C))
> PLUGIN=duplicateFunction.so
> PLUGIN_OBJECTS=duplicateFunction.o
>
> ALL_OBJECTS=$(PLUGIN_OBJECTS)
> ALL_TARGETS=$(PLUGIN) $(TEST_FILE)
>
> CPP_OPTIONS+=$(CPPFLAGS) $(shell $(LLVM_CONFIG) --cppflags) -MD -MP
> -I$(SRC_DIR)
>
> LD_OPTIONS+=$(LDFLAGS) $(shell $(LLVM_CONFIG) --ldflags)
>
> all: $(ALL_TARGETS)
>
> %.o : $(SRC_DIR)/%.cpp
> @echo Compiling $*.cpp
> $(QUIET)$(CXX) -c $(CPP_OPTIONS) $(CXXFLAGS) $<
>
> $(PLUGIN): $(PLUGIN_OBJECTS)
> @echo Linking $@
> $(QUIET)$(CXX) -o $@ $(LOADABLE_MODULE_OPTIONS) $(CXXFLAGS)
> $(LD_OPTIONS) $(PLUGIN_OBJECTS)
>
> RUN_FLAGS=-duplicateFunction
>
> $(TEST_FILE): $(TEST_C)
> clang -g -O3 -S -emit-llvm $^
> # clang -g -O0 -S -emit-llvm $^
> # clang -O0 -S -emit-llvm $^
> run:
> opt -load ./$(PLUGIN) $(RUN_FLAGS) < $(TEST_FILE) > /dev/null
2> after.s
> # opt -load ./$(PLUGIN) $(RUN_FLAGS) < $(TEST_FILE) > /dev/null
>
> clean:
> $(QUIET)rm -f $(ALL_OBJECTS) *.d $(PLUGIN) $(TEST_FILE)
>
>
> -include $(ALL_OBJECTS:.o=.d)
>
>
>
>
>
>
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>
>
Hi Shawn, did you build LLVM with assertions enabled? You should, since you then get helpful error messages rather than obscure crashes. Also, take a look at ArgumentPromotion.cpp as an example of the kind of thing you are trying to do. Ciao, Duncan.> Sorry for the inconvenient about the previous post. The files were not attached. > So I put them here again. > > 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. > > > Thank you in advance. > Shawn. > > > duplicateFunction.cpp > ============================================================================> > //===- 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; > } > }; /* 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. > 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(); > > // set the calling convention to C. > // so, we interoperate with C Code properly. > Function *tmp = cast<Function>(Fn); > tmp->setCallingConv(CallingConv::C); > > return true; > } > > bool DP::runOnFunction(Function &F) { > #if 0 > 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; > } > > > test.c > ===================================================================================> #include <stdio.h> > #include <stdlib.h> > > int v[200]; > int haha(int); > > int main() > { > int i; > int n=100; > > if ( !haha(n) ) > exit(-1); > > return 1; > } > > int haha(int n) > //int haha(int n, char* IOCallIDs) > { > int i; > for (i=1; i<n; i++) > v[i] = v[i-1] + v[i]; > > printf ("hahaha\n"); > return 1; > } > > Makefile > ===================================================================================> LLVM_CONFIG?=llvm-config > > # location of the source > # useful if you want separate source and object directories. > SRC_DIR?=$(PWD) > > #ifndef VERBOSE > # QUIET:=@ > #endif > > COMMON_FLAGS=-Wall -Wextra #-fvisibility=hidden > CFLAGS+=$(COMMON_FLAGS) $(shell $(LLVM_CONFIG) --cflags) > CXXFLAGS+=$(COMMON_FLAGS) $(shell $(LLVM_CONFIG) --cxxflags) > > #ifeq ($(shell uname),Darwin) > #LOADABLE_MODULE_OPTIONS=-bundle -undefined dynamic_lookup > #else > LOADABLE_MODULE_OPTIONS=-shared -Wl,-O1 > #endif > > TEST_C=test.c > TEST_FILE=$(subst .c,.s, $(TEST_C)) > PLUGIN=duplicateFunction.so > PLUGIN_OBJECTS=duplicateFunction.o > > ALL_OBJECTS=$(PLUGIN_OBJECTS) > ALL_TARGETS=$(PLUGIN) $(TEST_FILE) > > CPP_OPTIONS+=$(CPPFLAGS) $(shell $(LLVM_CONFIG) --cppflags) -MD -MP -I$(SRC_DIR) > > LD_OPTIONS+=$(LDFLAGS) $(shell $(LLVM_CONFIG) --ldflags) > > all: $(ALL_TARGETS) > > %.o : $(SRC_DIR)/%.cpp > @echo Compiling $*.cpp > $(QUIET)$(CXX) -c $(CPP_OPTIONS) $(CXXFLAGS) $< > > $(PLUGIN): $(PLUGIN_OBJECTS) > @echo Linking $@ > $(QUIET)$(CXX) -o $@ $(LOADABLE_MODULE_OPTIONS) $(CXXFLAGS) $(LD_OPTIONS) > $(PLUGIN_OBJECTS) > > RUN_FLAGS=-duplicateFunction > > $(TEST_FILE): $(TEST_C) > clang -g -O3 -S -emit-llvm $^ > # clang -g -O0 -S -emit-llvm $^ > # clang -O0 -S -emit-llvm $^ > run: > opt -load ./$(PLUGIN) $(RUN_FLAGS) < $(TEST_FILE) > /dev/null 2> after.s > # opt -load ./$(PLUGIN) $(RUN_FLAGS) < $(TEST_FILE) > /dev/null > > clean: > $(QUIET)rm -f $(ALL_OBJECTS) *.d $(PLUGIN) $(TEST_FILE) > > > -include $(ALL_OBJECTS:.o=.d) > > > > > > > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev