https://github.com/leejaymin/llvm8-tutorials-jemin/tree/master
해당 GitHub를 참고하여 호출되는 명령어를 출력하는 Pass를 제작해 보았다.
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();
}
};
}
namespace의 역할CallInstCountPass 클래스PassInfoMixin<CallInstCountPass>를 상속받는 Function-Level Pass 클래스PassInfoMixin은 LLVM이 제공하는 템플릿 클래스로, Pass 등록 및 동작 정의를 간편하게 할 수 있도록 함run 함수FunctionPassManager에 의해 각 함수마다 자동으로 호출됨CallInst를 검사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가 실행되도록 등록
- opt 실행
- PassPlugin 로드 (libMyPass.so)
- llvmGetPassPluginInfo() 실행
- registerPipelineParsingCallback 등록됨
- opt -passes="callinstcount" 해석됨
- "callinstcount" → CallInstCountPass() 객체 생성
- FunctionPassManager(FPM)에 Pass 등록됨
- FPM이 Module의 모든 Function에 대해 run() 호출
- 분석/출력 실행됨

#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;
});
}
};
}
#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에 있는 예시 코드로 사용하였다.

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