LLVM Pass для вставки внешнего вызова функции в битовый код LLVM - PullRequest
0 голосов
/ 28 июня 2018

Я пишу LLVM пропуск на инструмент C исходной программы. Я хочу вставить вызов функции перед каждой инструкцией ветвления, которая вызывает внешнюю функцию, например:

void print(int x){
    printf("x = %d\n", x);

    return;
}

Я хочу связать эту внешнюю функцию с C исходным кодом с помощью инструмента llvm-link, а затем обработать код с помощью инструмента opt.

Этот шаг, который я реализовал, выглядит следующим образом:

#include "llvm/Pass.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/IRBuilder.h"
#include <vector>

using namespace llvm;

namespace{
    struct ir_instrumentation : public ModulePass{
    static char ID;
    Function *monitor;

    ir_instrumentation() : ModulePass(ID) {}

    virtual bool runOnModule(Module &M)
    {
        std::vector<Type *> args;
        args.push_back(Type::getInt32Ty(M.getContext()));
        ArrayRef<Type*>  argsRef(args);
        FunctionType *FT = FunctionType::get(Type::getVoidTy(M.getContext()), args, false);
        Constant* myFunc = M.getOrInsertFunction("print", FT, NULL);
        minitor = cast<Function>(myFunc);


        for(Module::iterator F = M.begin(), E = M.end(); F!= E; ++F)
        {
            for(Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
            {
                for(BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE; ++BI)
                {
                    if(isa<BranchInst>(&(*BI)) )
                    {
                        errs() << "found a brach instruction!\n";
                        ArrayRef< Value* > arguments(ConstantInt::get(Type::getInt32Ty(M.getContext()), 5, true));
                        Instruction *newInst = CallInst::Create(monitor, arguments, "");
                        BB->getInstList().insert(BI, newInst); 
                        errs() << "Inserted the function!\n";
                    }

                }
            }
        }

        return true;
    }
};
char ir_instrumentation::ID = 0;
static RegisterPass<ir_instrumentation> X("ir-instrumentation", "LLVM IR Instrumentation Pass");

}

LLVM настроен и построен нормально с этим проходом, но когда я использую opt, я получаю это error:

opt: /llvm/lib/IR/Type.cpp:281:

llvm :: FunctionType :: FunctionType (llvm :: Type *, llvm :: ArrayRef, bool):

Утверждение `isValidReturnType (Result) &&" неверный тип возврата для функции "'не выполнено.

Я думаю, что проблема в чем-то вроде несоответствия между объявленным мной типом функции и внешней функцией (например, контекстом).

LLVM версия: LLVM версия 7.0.0svn

До сих пор я не решил проблему.

Спасибо

1 Ответ

0 голосов
/ 29 июня 2018

Я наконец смог решить эту проблему и успешно обработать битовый код LLVM. После многих проблем с функцией getOrInsertFunction я обнаружил, что в моем случае нет необходимости использовать этот метод. Я просто изменил свой пропуск на это:

#include "llvm/Pass.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/raw_ostream.h"

#include "llvm/IR/IRBuilder.h"

#include <vector>

using namespace llvm;

namespace{
struct ir_instrumentation : public ModulePass{
    static char ID;
    Function *monitor;

    ir_instrumentation() : ModulePass(ID) {}

    virtual bool runOnModule(Module &M)
    {
        errs() << "====----- Entered Module " << M.getName() << ".\n";

        int counter = 0;

        for(Module::iterator F = M.begin(), E = M.end(); F!= E; ++F)
        {
            errs() << "Function name: " << F->getName() << ".\n";
            if(F->getName() == "print"){
                monitor = cast<Function>(F);
                continue;
            }

            for(Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
            {
                for(BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE; ++BI)
                {
                    if(isa<BranchInst>(&(*BI)) )
                    {
                        errs() << "found a brach instruction!\n";
                        ArrayRef< Value* > arguments(ConstantInt::get(Type::getInt32Ty(M.getContext()), counter, true));
                        counter++;
                        Instruction *newInst = CallInst::Create(monitor, arguments, "");
                        BB->getInstList().insert(BI, newInst); 
                        errs() << "Inserted the function!\n";
                    }

                }
            }
        }

        return true;
    }
};
char ir_instrumentation::ID = 0;
static RegisterPass<ir_instrumentation> X("ir-instrumentation", "LLVM IR Instrumentation Pass");

}

Поскольку я знаю имя внешней функции, я могу просто найти его путем перебора всех функций модуля и затем использовать его по желанию.

Очевидно, что проблема была вызвана вызовом module->getOrInsertFunction и типом функции. Мой опыт говорит, что этот метод более полезен, когда вы хотите вставить новую функцию и объявить прототип своей собственной функции. Использование его для получения существующей функции является сложной задачей (например, установка правильного прототипа, ...)

Спасибо

...