LLVM | insert hook function with uintptr_t argument - c++

I want to insert below function:
void foo(uintptr_t addr) {}
Function type declaration:
std::vector<llvm::Type*> params = {Type::getInt64Ty(Context)};
FunctionType* funcTy = FunctionType::get(Type::getVoidTy(Context), params, false);
Call insertion:
llvm::IRBuilder<> builder(I);
builder.SetInsertPoint(bb, ++builder.GetInsertPoint());
// uintptr_t addr = 123213
ArrayRef< Value* > args(ConstantInt::get(Type::getInt64Ty(llvmContext), addr, false));
builder.CreateCall(F,args);
Got: Calling a function with a bad signature!"' failed.
Please help with the correct way of doing this

#arnt is correct. I guess you want the "addr" as an int to your hook function. Remember, this addr can't be statically determined by the compiler, but it's a dynamic address. So you need to replace your args with something like:
ArrayRef< Value* > args(CastInst::CreateIntegerCast(addr, F->getFunctionType()->getFunctionParamType(0), true, "", InsertPoint))
You can use your IRBuilder to do this. This is actually instrument a new instruction to dynamically convert an "addr" into a integer, then you can pass it to your hook function.

Related

How to Create a Load Instruction in LLVM, given Pointer to do the Load from?

I'm writing a LLVM pass where I create a function with integer pointer arguments. I need to implement the body of the function as well, and in order to do so, I need the integer values that are being pointed to. I am trying to create a load instruction that I can insert at the end of the basic block that contains the function body, but I am getting an error when doing so. Things compile fine, but when I run the pass, I get a generic error.
From what I've found about LLVM, there are usually ways to create instructions that don't involve using constructors, but I couldn't find a way to do that for load instructions, so I just used one of the constructors instead. After creating the function with arguments of the integer pointer type, this is the code that I'm using to do the load:
llvm::LoadInst operandLoad(llvm::Type::getInt32Ty(ctx), argList[0], "test", basicBlock);
If I comment the above line out, my pass runs fine. I'm unsure whether this is enough to diagnose the issue, so I'll include all the code to create the function (it's slightly simplified):
void createFunction(std::string functionName, llvm::LLVMContext &ctx, llvm::Module *module) {
std::vector<llvm::Type*> typeList = {llvm::Type::getInt32PtrTy(ctx)};
// Create function type
llvm::FunctionType *functionType = llvm::FunctionType::get(llvm::Type::getVoidTy(ctx), typeList, false);
// Create function
llvm::Function *function = llvm::Function::Create(functionType, llvm::Function::ExternalLinkage, functionName, module);
std::vector<llvm::Value*> argList;
for (llvm::Function::arg_iterator it = function->arg_begin(); it != function->arg_end(); ++it) {
argList.push_back(it);
}
llvm::BasicBlock *basicBlock = llvm::BasicBlock::Create(ctx, "entry", function);
llvm::LoadInst operandLoad(llvm::Type::getInt32Ty(ctx), argList[0], "test", basicBlock);
llvm::IRBuilder<> builder(ctx);
builder.SetInsertPoint(basicBlock);
builder.CreateRet(nullptr);
}
I'm sure this is a stupid question, so sorry about that. And thanks in advance!

Passing arguments as void pointers to a function

I got an array of functions to be called later as callbacks:
std::vector<std::function<void(void*)>> callbacks;
I do need to insert different kind of functions to this vector, that's why I choose void* to be the argument.
In one of these functions I needed an int, so I did like that:
void MyObject::MyTestCb(void* params) {
int i = *(int*)params;
...
}
...
callbacks.push_back(std::bind(&MyObject::MyTestCb, this, std::placeholders::_1));
When I call those callbacks, first I tried like this:
int index = 73;
void* params = (void*)&index;
callbacks[x](params);
But sometimes I wasn't received the value in the callback function! Most of the time were obtaining zero. May it is related due to being on a 64 bits machine?
Anyway, I tried this way then:
void* params = new int(73);
callbacks[x](params);
delete params;
And after some testing I didn't find any problem at all. However, is this last way the correct way to do it? Should it support any type as argument?

How to use custom type function pointer in C++

Condition
I use a framework that has an custom type as bellow:
typedef log (*CustomType) (
int timeStamp,
const char* data,
int dataSize,
void* userData,
int dataType,
int viewId
)
and MyClass init method as bellow:
MyClass_Init (void **output, CustomType video, CustomType audio, void* userData)
Question
I used init method like bellow but always receive error (error content is not displayed because i use a framework). pls point me what is missed.
CustomType videoInput;
CustomType audioInput;
void *output = malloc(sizeof(void*);
void *userData = malloc(sizeof(void*));
long result = MyClass_Init(&output, videoInput, audioInput, userData);
A number of things wrong with this code:
You can't intermix function pointers and method pointers. What it boils down to is that the this for a method has to be included in the method call signature. Since the function pointer doesn't include the this pointer (it is a function, not a method pointer), the two can not match.
Most C-based API includes some sort of reference value (most frameworks call those refCon, context or userData), so what you can do is create an adapter function that calls your method. The userData parameter in your CustomType parameter list looks like it is one of those (consult the docs to be sure).
You can probably provide a userData wherever you set MyClass_Init as your callback now. So, if that function to provide a callback to the library was called set_callback( MyCustomType callback, void* userData ), do something like
MyClass *obj = new MyClass; // Or however you create your object
set_callback( MyClassCallbackAdapterFunction, obj );
with an adapter function like:
log MyClassCallbackAdapterFunction( int timeStamp, const char* data, int dataSize, void* userData, int dataType, int viewId )
{
MyClass *myThis = (MyClass*) userData;
// Here you can now call myThis->MyClass_Init( ... ) however you want to.
}
The malloc( sizeof(void*) ) statements look like you're misunderstanding return parameters (also called "side effects" by some teachers). I don't have the docs to whatever API/library you're using, but I'm pretty certain you're supposed to not just pass in buffers the size of a pointer. Either you'd just provide a pointer on the stack in which a buffer will be returned, or you provide a whole buffer (e.g. an array) and its size, and that is where the callback will write to or so.

Calling a method from JIT code

I'm trying to call a method on an object from inside my compiled llvm JIT code.
I've read the answer here ( Can I bind an existing method to a LLVM Function* and use it from JIT-compiled code? ) but my case is slightly different, as my method requires an argument.
If I'm understanding everything correctly, I need to wrap my method with a function, but how can I store the pointer to my instance to use as the first argument when calling?
Here's a short example (omited some irrelevant parts)
class Foo:
{
public:
Foo();
float getValue(char * name);
};
float fooWrap(Foo *foo, char * name)
{
foo->getValue(name);
}
Foo::Foo()
{
// snipped llvm init stuff
std::vector<llvm::Type*> fun_args;
fun_args.push_back(llvm::Type::getInt8Ty(context)); // Pointer to this instance (pretty sure is wrong)
fun_args.push_back(llvm::Type::getInt8PtrTy(context)); // char array *
llvm::FunctionType *FT = llvm::FunctionType::get(llvm::Type::getFloatTy(context), fun_args, false);
llvm::Function * F = llvm::Function::Create(FT, llvm::Function::ExternalLinkage, "foo", module);
engine->addGlobalMapping(F, &fooWrap);
// later
llvm::Value *instance = llvm::ConstantInt::get(context, llvm::APInt((intptr_t) &this)); // wont compile, can't construct APInt from intptr_t
std::vector<llvm::Value*> args;
args.push_back(instance);
args.push_back(builder.CreateGlobalStringPtr("test"));
builder.CreateCall(F, args);
}
Any help would be greatly appreciated.
The argument type ended up being:
llvm::Type::getIntNTy(context, sizeof(uintptr_t)*8)
And the value was set with:
llvm::Value *instance = llvm::ConstantInt::get(llvm::Type::getIntNTy(context, sizeof(uintptr_t)*8), (uintptr_t) this);
This ensured that the pointer size was always correct for the compiled platform.
Seems to me like your question can be summed up by:
How to convert some object pointer in my code to an LLVM Value?
And your approach is correct - create a constant int with the value of the pointer as casted to an integer. Your error is just an incorrect usage of APInt's constructor - and in fact you don't need an APInt to start with, you can just do ConstantInt::get(context, (uintptr_t)this) (which works by constructing an APInt itself, as you can see in its implementation).

Replacing instructions in LLVM

I want to replace the call to malloc with call to cumemhostalloc function.
float *h_A=(float *)malloc(size);
should be replaced with
cuMemHostAlloc((void **)&h_A,size,2);
I use the following code for this,
*if (dyn_cast<CallInst> (j))
{
Ip=cast<Instruction>(j);
CastInst* ci_hp = new BitCastInst(ptr_h_A, PointerTy_23, "" );
BB->getInstList().insert(Ip,ci_hp);
errs()<<"\n Cast instruction is inserted"<<*ci_hp;
li_size = new LoadInst(al_size, "", false);
li_size->setAlignment(4);
BB->getInstList().insert(Ip,li_size);
errs()<<"\n Load instruction is inserted"<<*li_size;
ConstantInt* const_int32_34 = ConstantInt::get(M->getContext(), APInt(32, StringRef("2"), 10));
std::vector<Value*> cumemhaparams;
cumemhaparams.push_back(ci_hp);
cumemhaparams.push_back(li_size);
cumemhaparams.push_back(const_int32_34);
CallInst* cumemha = CallInst::Create(func_cuMemHostAlloc, cumemhaparams, "");
cumemha->setCallingConv(CallingConv::C);
cumemha->setTailCall(false);
AttrListPtr cumemha_PAL;
cumemha->setAttributes(cumemha_PAL);
ReplaceInstWithInst(callinst->getParent()->getInstList(), j,cumemha);*
}
But I get the following error,
/home/project/llvmfin/llvm-3.0.src/lib/VMCore/Value.cpp:287: void llvm::Value::replaceAllUsesWith(llvm::Value*): Assertion `New->getType() == getType() && "replaceAllUses of value with new value of different type!"' failed.
Is it because the call to malloc is replaced with a function that has a different signature?
Almost. Call to malloc produce a value, your function - does not. So, you have to replace call with a load, not with another call
Also, looking into your code:
Do not play with instlists directly. Use IRBuilder + iterators instead
You can check for CallInst and declare var at the same time, no need to additional cast to Instruction.