基础知识和框架请看
代码主干
遍历函数
遍历basicblock
遍历statement
找到目标操作符
打印目标操作符所在行代码
打印目标操作符数据流上级
打印目标操作符数据流下级
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "list"
using namespace llvm;
namespace {
//定义 First 类继承自 FunctionPass
struct First : public FunctionPass {
static char ID; // Pass ID
std::string str;
First() : FunctionPass(ID) {}
std::list<Instruction *>::iterator itor_former; //定义迭代器
int num_function = 0; // 用来记录多少个函数
bool runOnFunction(Function &F) override { //这里是一个函数一个函数的往里面传的数据
errs() << F.getName() << "\n"; //显示函数名称
errs() << "num_function=" << num_function <<"\n"; //num_function=0
num_function++;
// 打印call func的句子
for (User *U : F.users()) {
if (Instruction *Inst = dyn_cast<Instruction>(U)) {
errs() << "F is used in instruction:";
errs() << *Inst << "\n";
}
}
// raw_string_ostream rso(str);
// StringRef name("Graph.dot"); //生成图
// std::ofstream output_CFG_file(
// "output.txt"); //定义输出文件
// output_CFG_file << "hello world:"; // 向文件内输出
// output_CFG_file.close();
//遍历函数中的basicblock
for (Function::iterator BB = F.begin(); BB != F.end(); ++BB) {
errs() << "块的长度 size:BB->size() "<< BB->size() <<"\n";//显示basicblock的名字和大小
//在BB中遍历statement
for(BasicBlock::iterator i = BB->begin(); i!=BB->end(); i++){
// 打印块内statement所有数据
// errs() << "每一行的数据和地址" << &*i ; //打印ir块里面的所有行,和地址
// errs() << " *i:" << *i ; //打印ir块里面的所有行,和地址
// errs() << " 操作符i->getOpcodeName(): " << i->getOpcodeName() << "\n"; //打印ir块里面的所有行,和地址
//dyn_cast<>操作符是一个“检查转换”操作。它检查操作数是否属于指定的类型
//判断本行中是否包含操作符add,打印这行数据
Instruction *inst = dyn_cast<Instruction>(i);
if(inst->getOpcode() == Instruction :: Add || inst->getOpcode() == Instruction::Br || inst->getOpcode() == Instruction::ICmp){
for(User *U :inst ->users())
{
// 打印add行
// errs() <<"dyn_cast(U)"<<*dyn_cast(U) << "\n";
if(Instruction *Inst = dyn_cast<Instruction>(U))
{
//%13 = add nsw i32 %12, 2add
errs()<<"\n操作符定位到 of add/icmp used in : "<<*inst << " " << inst->getOpcodeName() <<"\n";
errs()<<"操作符下一级 : "<<*Inst << "\n";
}
}
// 输出其所使用的所有operands(操作数)就是加数被加数
// %16 = add nsw i32 %15, 1
// %15 = load i32, i32* %7, align 4和i32 1
for(Use &U :inst ->operands())
{
Value *v =U.get();
errs()<<"input of add originate from : " <<*v<<"\n";
}
}
}
// for (BasicBlock *SuccBB : successors(curBB)) {
// errs() << "&*(SuccBB->begin()):" << &*(SuccBB->begin()) << "\n";
// }
}
return false;
}
};
}
char First::ID = 0; //初始化 Pass ID
//最后注册 FirstPass, 指定命令行参数为 First
static RegisterPass <First>X("First", "First Pass");
#include
int fun1(){
printf("%s\n", "hello");
return 25;
}
int fun2(){
printf("%s\n", "fun2");
return 23;
}
int main(int argc, char const *argv[]){
int b=0;
int i = 0;
for (i = 0; i < 23; ++i){
b+=2;
}
printf("%d\n", b);
return 0;
}
转化为ir文件或者bc文件应用1中有涉及
zjq@DESKTOP-O28RVV3:test2_$ cat run.sh
cd build/ && make && cd ..
opt -load build/libFirstPass.so -First hello.ll
zjq@DESKTOP-O28RVV3:test2_$ source run.sh
[100%] Built target FirstPass
WARNING: You're attempting to print out a bitcode file.
This is inadvisable as it may cause display problems. If
you REALLY want to taste LLVM bitcode first-hand, you
can force output with the `-f' option.
fun1
num_function=0
块的长度 size:BB->size() 2
fun2
num_function=1
F is used in instruction: %18 = call i32 @fun2()
块的长度 size:BB->size() 2
main
num_function=2
块的长度 size:BB->size() 12
input of add originate from :
; <label>:8: ; preds = %14, %2
%9 = load i32, i32* %7, align 4
%10 = icmp slt i32 %9, 23
br i1 %10, label %11, label %17
块的长度 size:BB->size() 3
操作符定位到 of add/icmp used in : %10 = icmp slt i32 %9, 23 icmp
操作符下一级 : br i1 %10, label %11, label %17
input of add originate from : %9 = load i32, i32* %7, align 4
input of add originate from : i32 23
input of add originate from : %10 = icmp slt i32 %9, 23
input of add originate from :
; <label>:17: ; preds = %8
%18 = call i32 @fun2()
%19 = load i32, i32* %6, align 4
%20 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.3, i32 0, i32 0), i32 %19)
ret i32 0
input of add originate from :
; <label>:11: ; preds = %8
%12 = load i32, i32* %6, align 4
%13 = add nsw i32 %12, 2
store i32 %13, i32* %6, align 4
br label %14
块的长度 size:BB->size() 4
操作符定位到 of add/icmp used in : %13 = add nsw i32 %12, 2 add
操作符下一级 : store i32 %13, i32* %6, align 4
input of add originate from : %12 = load i32, i32* %6, align 4
input of add originate from : i32 2
input of add originate from :
; <label>:14: ; preds = %11
%15 = load i32, i32* %7, align 4
%16 = add nsw i32 %15, 1
store i32 %16, i32* %7, align 4
br label %8
块的长度 size:BB->size() 4
操作符定位到 of add/icmp used in : %16 = add nsw i32 %15, 1 add
操作符下一级 : store i32 %16, i32* %7, align 4
input of add originate from : %15 = load i32, i32* %7, align 4
input of add originate from : i32 1
input of add originate from :
; <label>:8: ; preds = %14, %2
%9 = load i32, i32* %7, align 4
%10 = icmp slt i32 %9, 23
br i1 %10, label %11, label %17
块的长度 size:BB->size() 4
zjq@DESKTOP-O28RVV3:test2_$
通过代码中定位操作符,然后得到对应操作符的上下文关系, cfg和dfg非常方便
具体细节代码中有注释
具体流程请跳转到1\2两节