function call replacement

Hi everyone,

I am trying to replace the call of a certain function with a call to another function. It would for example replace the following:

%call = tail call noalias i8* @func(i64 10)

by
%call = tail call noalias i8* @other_func(i64 10)

I managed to declare other_func correctly but I am having troubles to understand how I should proceed to do the replacement.

I tried to use ReplaceInstWithInst function as follows:

CallInst *call_to_other_func_inst = IRBuilder.CreateCall(ptr_to_other_func, args);
ReplaceInstWithInst(call_to_func_inst, newI);

LLVM builds correctly but the instrumentation crashes at optimization time. I know this isn’t the correct way to do it because IRBuilder generates IR and I just want to have an instance of a CallInst. But I don’t see how it is supposed to be done?

There are methods to create CallInst in the Instruction.h file but those needs to give an inserting point. Shoud I insert the call to other_func before the one to func and just remove the call instruction to func?

Thanks for your help,

Pierre

Few things you have to be careful with:

  1. Create args properly and make sure the actual and formal parameter types should be same.

If not add a cast.

  1. Make sure the return types are same.

  2. Set the calling conventions if any.

  3. Replace use if any.

  4. Then replace the instruction.

CallSite CS(Call);

SmallVector<Value *, 8> Args(CS.arg_begin(), CS.arg_end());

CallInst *NewCI = CallInst::Create(NewFunc, Args);

NewCI->setCallingConv(NewFunc->getCallingConv());

if (!Call->use_empty())

Call->replaceAllUsesWith(NewCI);

ReplaceInstWithInst(Call, NewCI);

Regards,

Ashutosh

Do you have assertions enabled? If so, is the crash an assertion failure and, if so, which assertion is failing? It’s nearly impossible to tell what the problem is just by knowing that it is crashing. Yes. You need to place the new call instruction within the same basic block as the old call instruction. Placing it right before the old call instruction is a good place. The code that Ashutosh provided is what I’d use to do what you’re doing. Regards, John Criswell

Hi,

Thanks both of you for the help. I just missed that Create function had many optional arguments… sorry for that. However my problem wasn’t coming from here (IRBuilder CreateCall function still return a pointer to CallInst so I just added 2 times the call?). I didn’t wanted to detail the all issue previously because I knew I had a problem with my syntax. So here’s my problem:

I am doing this replacement operation in a FunctionPass (this is no restriction, I could do it on a ModulePass if that’s a solution). On each Function given I do an iteration over the instructions and replace (if it’s a call to the right function) the call. It’s like this:

bool FDPFunction::runOnFunction(Function &F) {

bool res = false;

TLI = &getAnalysis().getTLI();

for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) {
Instruction *I = &*i;

if (!I) {
errs() << “error: null pointer instruction\n”;
break;
} else if (isMyFunctionCall(I, TLI)) {
errs() << “found a call to the function to replace\n”;

res = true;

replacement_function(I);
} else {
errs() << “default: trash instruction\n”;
}
}

return res;
}

The problem is that after the first replacement, the iterator becomes a null pointer. With the break instruction the program is correctly instrumented for the first call (about that: what is the use of replaceAllUsesWith function? I thought it would replace all uses of the function… but just one is done). I can then link it and execute with lli (I still get a: “*** Error in `lli’: corrupted double-linked list: 0xaddress ***” but after the whole execution is done).

But if I remove the break and the if condition associated, well I get a null pointer exception : Assertion `Val && “isa<> used on a null pointer”’ failed

I tried to clone the current instruction to not modify the iterator but the ReplaceInstWithInst will cause troubles (probably because a copied instruction has no parents):

#0 0x0000000002a95b5c llvm::sys::PrintStackTrace(llvm::raw_ostream&) /home/pierre/Desktop/llvm/lib/Support/Unix/Signals.inc:400:0
#1 0x0000000002a95edf PrintStaI tried to clone the current instruction to not modify the iterator but the ReplaceInstWithInst will cause troublesckTraceSignalHandler(void*) /home/pierre/Desktop/llvm/lib/Support/Unix/Signals.inc:468:0
#2 0x0000000002a94145 llvm::sys::RunSignalHandlers() /home/pierre/Desktop/llvm/lib/Support/Signals.cpp:44:0
#3 0x0000000002a953a8 SignalHandler(int) /home/pierre/Desktop/llvm/lib/Support/Unix/Signals.inc:254:0
#4 0x00007fe358d3dd10 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x10d10)
#5 0x00000000011fe489 llvm::iplist<llvm::Instruction, llvm::SymbolTableListTraitsllvm::Instruction >::insert(llvm::ilist_iteratorllvm::Instruction, llvm::Instruction*) /home/pierre/Desktop/llvm/include/llvm/ADT/ilist.h:415:0
#6 0x0000000002abc20d llvm::ReI tried to clone the current instruction to not modify the iterator but the ReplaceInstWithInst will cause troublesplaceInstWithInst(llvm::SymbolTableListllvm::Instruction&, llvm::ilist_iteratorllvm::Instruction&, llvm::Instruction*) /home/pierre/Desktop/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp:198:0
#7 0x0000000002abc2a5 llvm::ReplaceInstWithInst(llvm::Instruction*, llvm::Instruction*) /home/pierre/Desktop/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp:210:0

Any idea on what could be the cause of the null pointer and how to avoid it?

Thanks a lot for your time!

Pierre

Hi again,

that’s weird… I continued the implementation of the replaced function (not touched the FunctionPass, just the runtime function) and I have no more the “*** Error in `lli’: corrupted double-linked list: 0xaddress ***” error message when I run the linked bitcode file…

Anyway the issue of the null pointer iterator still is here but now I assume it doesn’t imply the error in lli?

Hope you have any lead on that point,

Pierre

You might be invalidating the iterator after inserting the first CallInst. There are multiple ways to solve this problem: Regards, John Criswell

You might be invalidating the iterator after inserting the first CallInst.
There are multiple ways to solve this problem:

   1. Make your pass derive from the InstVistor class and implement a
   visitCallInst() method. I believe the iterators in the InstVistor class do
   not get invalidated when new instructions are added.
   2. Iterate over all the instructions first and record the ones to
   replace in a container (e.g., a std::vector<>). A second loop iterates
   over the container and replaces all the CallInsts stored therein.
   3. Look up the iterator invalidation rules for the instruction
   iterator and use the iterator in a way that does not invalidate the
   iterator.

Good call, method 2. is working fine. I remember seeing such pattern in

BoudsChecking code. I guess I am not the first having troubles with this.

I took a quick look at the iterator problem
- For the cloned instruction, the problem is it has no parents and I guess
it implies it has no link with previous or next instructions. So some
nullpointers will appear when inserting the instruction because it will try
to build the double linked list of instructions (I think that's the
algorithmic structure employed).
  - For the regular iterator the problem might be just the same. As it is a
double linked list, when you replace the current instruction with another
the current instruction probably is erased. I already made the changes so I
won't try to generate the error again but I thinks that makes sense.

Regards,

John Criswell

Thanks a lot! About the lli error it appears to have an undefined

behavior. Some times it runs correctly, most of the times it freezes and
sometimes I get the lli error. Anyway, the fact the error says that the
double-linked list is corrupted make sense with my thoughts about the
iterator issue.

Pierre