Insert a call to a function that takes an LLVM instruction as argument - Calling a function with a bad signature!

Hi,

I would like to instrument LLVM IR such that whenever
a find a load, I insert a call to a self-implemented function
that takes this load as an argument and then do some
operations on the load.

The C++ signature of the function call is:

void analyzeInstruction(Instruction &I) {..}

which in LLVM IR corresponds to (if I am not mistaken):

define void @analyzeInstruction(%"class.llvm::Instruction"* %I).

For that I write a pass such that whenever I find a load, I insert

the following function call:

  virtual bool runOnBasicBlock(Function::iterator &BB) {

            for(BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE; ++BI) {

                    if(isa<LoadInst>(&(*BI))){

                        LoadInst *CI = dyn_cast<LoadInst>(BI);

Instruction *CI = dyn_cast<Instruction>(BI);

    CallInst* void_114 = CallInst::Create(analyze_func, CI, "");

    void_114->setCallingConv(CallingConv::C);

  void_114->setTailCall(false);

  AttributeSet void_114_PAL;

  void_114->setAttributes(void_114_PAL);

BB->getInstList ().insertAfter ((Instruction *)CI , void_114 );

}
}
}

Where analyze_func is defined as:

Function *analyze_func;
PointerType* PointerTy_420;
PointerType* PointerTy_421;
FunctionType* FuncTy_analyzeInstruction;
StructType *StructTy_class_llvm__LoadInst;

StructTy_class_llvm__LoadInst= M.getTypeByName("class.llvm::LoadInst");
if (!StructTy_class_llvm__LoadInst) {
StructTy_class_llvm__LoadInst = StructType::create(M.getContext(), "class.llvm::LoadInst");
}

PointerTy_420 = PointerType::get(StructTy_class_llvm__LoadInst, 0);

std::vector<Type*> FuncTy_analyzeInstruction_args;
FuncTy_analyzeInstruction_args.push_back(PointerTy_420);

FuncTy_analyzeInstruction = FunctionType::get(
  Type::getVoidTy(M.getContext()),
  FuncTy_analyzeInstruction_args,
  false);

analyze_func = M.getFunction("analyzeInstruction");
if (!analyze_funcion){

analyze_func = Function::Create(
FuncTy_analyzeInstruction,
   GlobalValue::ExternalLinkage,
   "analyzeInstruction", &M
  );
analyze_func->setCallingConv (CallingConv::C);
}

The problem is that when the function call is going to be created, I get
the error that the function has bad signature because the expected type
of the argument according to the function definition is:

FTy->getParamType(i) -> %"class.llvm::LoadInst"*

but the type of the argument is the actual type of the value loaded, which
is:

Args[i]->getType() -> i32

How can I create the function call such that the function signature is correct?

Many thanks in advance,

Victoria

Hi,

I would like to instrument LLVM IR such that whenever
a find a load, I insert a call to a self-implemented function
that takes this load as an argument and then do some
operations on the load.

The C++ signature of the function call is:

void analyzeInstruction(Instruction &I) {..}

which in LLVM IR corresponds to (if I am not mistaken):

define void @analyzeInstruction(%"class.llvm::Instruction"* %I).

This means just that you have a pointer to a type with the name
%"class.llvm::Instruction". This type does not have need to have anything in common with the C++ type llvm::Instruction, but totally depends on how it is defined in this LLVM-module. Looking at your code"

> StructTy_class_llvm__LoadInst=M.getTypeByName("class.llvm::LoadInst");
> if (!StructTy_class_llvm__LoadInst) {
> StructTy_class_llvm__LoadInst = StructType::create(M.getContext(), "class.llvm::LoadInst");
> }

You seem to define an llvm::Instructions as an empty struct.

As far as I remember you just want to use this parameter to identify a specific LLVM-IR instruction in your library. For this a simple *i8 or just a i64 would be enough. Furthermore, you also need to forward the actual value loaded to ensure the function call remains related to the instruction you analyze. You could possibly use something like:

define void @analyzeInstruction(i64 %Identifier, i64 %LoadedValue)

For that I write a pass such that whenever I find a load, I insert

the following function call:

   virtual bool runOnBasicBlock(Function::iterator &BB) {

             for(BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE; ++BI) {

                     if(isa<LoadInst>(&(*BI))){

                         LoadInst *CI = dyn_cast<LoadInst>(BI);

You could also use the IR-Builder. It has a very convenient interface to create functions.

Instruction *CI = dyn_cast<Instruction>(BI);

     CallInst* void_114 = CallInst::Create(analyze_func, CI, "");

     void_114->setCallingConv(CallingConv::C);

I believe this is default anyway.

   void_114->setTailCall(false);

That should also be default.

   AttributeSet void_114_PAL;

   void_114->setAttributes(void_114_PAL);

I don't understand that piece of code. I am more familiar to the IRBuilder.

Though what you probably want to do is to pass two parameters:

1) The value loaded (possibly zeroextended/truncated to i64)

2) An identifier for this specific LLVM-IR instruction. You could
possibly just use 'CI', the value of the pointer that points to this
instruction. Using the IR builder, you can create an llvm::Value that represents this pointer as an integer constant.

BB->getInstList ().insertAfter ((Instruction *)CI , void_114 );

}

Where analyze_func is defined as:

  Function *analyze_func;
PointerType* PointerTy_420;
PointerType* PointerTy_421;

FunctionType* FuncTy_analyzeInstruction;
StructType *StructTy_class_llvm__LoadInst;

StructTy_class_llvm__LoadInst= M.getTypeByName("class.llvm::LoadInst");
  if (!StructTy_class_llvm__LoadInst) {
  StructTy_class_llvm__LoadInst = StructType::create(M.getContext(), "class.llvm::LoadInst");
  }

PointerTy_420 = PointerType::get(StructTy_class_llvm__LoadInst, 0);

  std::vector<Type*> FuncTy_analyzeInstruction_args;
  FuncTy_analyzeInstruction_args.push_back(PointerTy_420);

If you use the interface above, those should be just two i64 values.

FuncTy_analyzeInstruction = FunctionType::get(
   Type::getVoidTy(M.getContext()),
   FuncTy_analyzeInstruction_args,
   false);

analyze_func = M.getFunction("analyzeInstruction");
if (!analyze_funcion){

  analyze_func = Function::Create(
  FuncTy_analyzeInstruction,
    GlobalValue::ExternalLinkage,
    "analyzeInstruction", &M
   );
  analyze_func->setCallingConv (CallingConv::C);
}

The problem is that when the function call is going to be created, I get
the error that the function has bad signature because the expected type
of the argument according to the function definition is:

FTy->getParamType(i) -> %"class.llvm::LoadInst"*

but the type of the argument is the actual type of the value loaded, which
is:

Args[i]->getType() -> i32

How can I create the function call such that the function signature is correct?

I gave some ideas above. Let me know if you have further questions.

Tobias