LLVM Pass TypeFinder

2023/02/18 LLVM 共 3443 字,约 10 分钟

获取结构体信息

LLVM Pass 的内容, Hello.cpp 如下:

#include "llvm/IR/Function.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
// llvm::TypeFinder
#include "llvm/IR/TypeFinder.h"

using namespace llvm;

namespace {
struct SkeletonPass : public FunctionPass {
  static char ID;
  SkeletonPass() : FunctionPass(ID) {}

  virtual bool runOnFunction(llvm::Function& F) {
    // 解析 AST
    llvm::TypeFinder StructTypes;
    const Module& M = *F.getParent();
    StructTypes.run(M, true);
    // 迭代所有的结构体
    for (auto* STy : StructTypes) {
      // 迭代结构体中的成员
      for (auto field : STy->elements()) {
        errs() << *STy << " ==> " << *field << "\n";
      }
    }
    return false;
  }
};
}  // namespace

char SkeletonPass::ID = 0;

static RegisterPass<SkeletonPass> X("rhpass", "Hello World Pass");

// Automatically enable the pass.
// http://adriansampson.net/blog/clangpass.html
static void registerSkeletonPass(const PassManagerBuilder&,
                                 legacy::PassManagerBase& PM) {
  PM.add(new SkeletonPass());
}
static RegisterStandardPasses RegisterMyPass(
    PassManagerBuilder::EP_EarlyAsPossible,
    registerSkeletonPass);

用于测试结构体的样本 main.c 的内容如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Human {
    size_t age;
    char name[32];
} Human;

typedef struct Student {
    Human man;
    size_t score;
} Student;

typedef struct Teacher {
    Human man;
    char title[32];
    size_t salary;
} Teacher;

typedef struct ClassRoom {
    size_t id;
    Teacher teacher;
    Student student[50];
} ClassRoom;


typedef struct School {
    char name[100];
    ClassRoom classrooms[100];
} School;


int main(int argc, const char** argv) {
    printf("======  Start  ======\n");
    Human p1, p2;
    Student s1;
    Teacher t1;
    ClassRoom c;
    School s;
    p1.age = 18;
    strncpy(p1.name, "JERRY", sizeof("JERRY"));
    p2.age = 42;
    strncpy(p2.name, "TOM", sizeof("TOM"));
    s1.man = p1;
    s1.score = 90;
    t1.man = p2;
    strncpy(t1.title, "Professor", sizeof("Professor"));
    t1.salary = 500000;
    c.id = 5;
    c.teacher = t1;
    c.student[0] = s1;
    strncpy(s.name, "Harvard University", sizeof("Harvard University"));
    s.classrooms[0] = c;
    printf("====== Finish ======\n");
    return 0;
}

使用以下命令构建并测试 Pass:

# 删除生成的中间文件
rm -f *.so *.elf *.ll

# 构建 LLVM Pass
clang `llvm-config --cxxflags` -Wl,-znodelete -fno-rtti -fPIC -shared Hello.cpp -o LLVMHello.so `llvm-config --ldflags`
# 使用 Pass 编译样本
clang -flegacy-pass-manager -g -Xclang -load -Xclang ./LLVMHello.so main.c -o main.elf

# 运行样本
./main.elf

输出如下:

%struct.Human = type { i64, [32 x i8] } ==> i64
%struct.Human = type { i64, [32 x i8] } ==> [32 x i8]
%struct.Student = type { %struct.Human, i64 } ==> %struct.Human = type { i64, [32 x i8] }
%struct.Student = type { %struct.Human, i64 } ==> i64
%struct.Teacher = type { %struct.Human, [32 x i8], i64 } ==> %struct.Human = type { i64, [32 x i8] }
%struct.Teacher = type { %struct.Human, [32 x i8], i64 } ==> [32 x i8]
%struct.Teacher = type { %struct.Human, [32 x i8], i64 } ==> i64
%struct.ClassRoom = type { i64, %struct.Teacher, [50 x %struct.Student] } ==> i64
%struct.ClassRoom = type { i64, %struct.Teacher, [50 x %struct.Student] } ==> %struct.Teacher = type { %struct.Human, [32 x i8], i64 }
%struct.ClassRoom = type { i64, %struct.Teacher, [50 x %struct.Student] } ==> [50 x %struct.Student]
%struct.School = type { [100 x i8], [100 x %struct.ClassRoom] } ==> [100 x i8]
%struct.School = type { [100 x i8], [100 x %struct.ClassRoom] } ==> [100 x %struct.ClassRoom]
======  Start  ======
====== Finish ======

关键 API 说明

llvm::TypeFinder StructTypes;
// 获取 Function 的 parent, 也就是当前所在模块
const Module& M = *F.getParent();
// 这里不知道为啥不能直接用 runOnModule 中的 Module
// 获取模块中的所有结构体, 第二个参数表示是否只寻找明明结构体
StructTypes.run(M, true);
// 迭代所有的结构体
for (auto* STy : StructTypes) {
    // 迭代结构体中的成员
    for (auto field : STy->elements()) {
        errs() << *STy << " ==> " << *field << "\n";
    }
}

文档信息

搜索

    Table of Contents