LLVM Pass CallInstCount

안상준·2025년 8월 6일

LLVM

목록 보기
7/12
post-thumbnail

https://github.com/leejaymin/llvm8-tutorials-jemin/tree/master
해당 GitHub를 참고하여 호출되는 명령어를 출력하는 Pass를 제작해 보았다.

Code

Pass class

namespace {
class CallInstCountPass : public PassInfoMixin<CallInstCountPass> {
public:
    PreservedAnalyses run(Function &F, FunctionAnalysisManager &) {
        for (auto &BB : F) {
            for (auto &I : BB) {
                if (auto *CI = dyn_cast<CallInst>(&I)) {
                    if (Function *calledFunc = CI->getCalledFunction()) {
                        errs() << calledFunc->getName() << "\n";
                    } else {
                        errs() << "Indirect Call or External Function\n\n";
                    }
                }
            }
        }
        return PreservedAnalyses::all();
    }
};
}

주요 구성 요소 설명

1. namespace의 역할

  • 익명 네임스페이스를 사용하면 이 파일 내부에서만 접근 가능한 코드 범위를 정의 가능
  • 이는 다른 Pass나 라이브러리와의 심볼 충돌을 방지하기 위한 안전장치

2. CallInstCountPass 클래스

  • PassInfoMixin<CallInstCountPass>를 상속받는 Function-Level Pass 클래스
  • PassInfoMixin은 LLVM이 제공하는 템플릿 클래스로, Pass 등록 및 동작 정의를 간편하게 할 수 있도록 함
    템플릿 인자로 자기 자신을 전달하는 CRTP(Curiously Recurring Template Pattern) 구조를 사용

3. run 함수

  • Pass의 핵심 로직이 동작하는 진입점
  • 이 함수는 FunctionPassManager에 의해 각 함수마다 자동으로 호출됨
  • 내부적으로 BasicBlock → Instruction 순으로 순회하며, CallInst를 검사
    • 직접 호출이면 함수 이름을 출력하고,
    • 간접 호출이거나 외부 함수 호출일 경우 별도 메시지를 출력

Pass 등록

extern "C" ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() {
    return {
        LLVM_PLUGIN_API_VERSION,
        "CallInstCountPass", LLVM_VERSION_STRING,
        [](PassBuilder &PB) {
            PB.registerPipelineParsingCallback(
                [](StringRef Name, FunctionPassManager &FPM,
                   ArrayRef<PassBuilder::PipelineElement>) {
                    if (Name == "callinstcount") {
                        FPM.addPass(CallInstCountPass());
                        return true;
                    }
                    return false;
                });
        }
    };
}
  • llvmGetPassPluginInfo플러그인 Pass를 등록하기 위한 엔트리 함수
  • registerPipelineParsingCallback을 통해 사용자가 명령어로 "callinstcount"라고 입력하면 해당 Pass가 실행되도록 등록
    1. opt 실행
    2. PassPlugin 로드 (libMyPass.so)
    3. llvmGetPassPluginInfo() 실행
    4. registerPipelineParsingCallback 등록됨
    5. opt -passes="callinstcount" 해석됨
    6. "callinstcount" → CallInstCountPass() 객체 생성
    7. FunctionPassManager(FPM)에 Pass 등록됨
    8. FPM이 Module의 모든 Function에 대해 run() 호출
    9. 분석/출력 실행됨

전체 코드

#include "llvm/IR/PassManager.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Passes/PassPlugin.h"

using namespace llvm;

namespace {
class CallInstCountPass : public PassInfoMixin<CallInstCountPass> {
public:
    PreservedAnalyses run(Function &F, FunctionAnalysisManager &) {
        // errs() << "[*] Function: " << F.getName() << "\n";

        for (auto &BB : F) {
            for (auto &I : BB) {
                if (auto *CI = dyn_cast<CallInst>(&I)) {
                    if (Function *calledFunc = CI->getCalledFunction()) {
                        errs() << calledFunc->getName() << "\n";
                    } else {
                        errs() << "Indirect Call or External Function : ";
                        CI->print(errs());
                        errs() << "\n";
                    }
                }
            }
        }

        return PreservedAnalyses::all();
    }
};
} // end anonymous namespace

// Plugin registration
extern "C" ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() {
    return {
        LLVM_PLUGIN_API_VERSION,
        "CallInstCountPass", LLVM_VERSION_STRING,
        [](PassBuilder &PB) {
            PB.registerPipelineParsingCallback(
                [](StringRef Name, FunctionPassManager &FPM,
                   ArrayRef<PassBuilder::PipelineElement>) {
                    if (Name == "callinstcount") {
                        FPM.addPass(CallInstCountPass());
                        return true;
                    }
                    return false;
                });
        }
    };
}

result

#include <stdio.h>

int add(int x, int y);

int main(){
  int x = 1;
  int y = 2;
  printf("Hello world!\n");
  printf("%d + %d = %d \n",x,y,add(x,y));
  return 0;
}

int add(int x, int y){
  return x+y;
}

코드는 GitHub에 있는 예시 코드로 사용하였다.

실행 결과 잘 나온 것을 확인할 수 있다.

0개의 댓글