LLVM Pass开发:如何获取函数实参在.ll文件中的对应名称?
解决LLVM Pass中获取函数调用实参名称的问题
首先得指出你代码里的核心误区:你现在遍历的是被调用函数的形参(fct->arg_begin()),而不是Call/Invoke指令里传递的实参。这就是为什么你拿到的是空字符串——被调用函数的形参可能没有被命名,而你在.ll文件里看到的@_ZN2xi9spawnable2f2E是调用时传递的第一个实参(一个全局变量),和被调用函数的形参完全是两回事。
正确的做法:遍历CallInst/InvokeInst的操作数
CallInst和InvokeInst的操作数列表里,第一个元素是被调用的函数(或函数指针),从第二个元素开始才是传递的实参。你需要遍历这些操作数,然后根据操作数的类型来获取对应的名称:
- 如果实参是
GlobalValue(比如全局变量、函数),可以直接用getName()拿到它的符号名; - 如果实参是
Instruction(比如寄存器值,像%1、%9),它的名字可能是空,除非IR里显式命名或者有调试信息; - 如果是常量(比如
i1 zeroext %9里的%9是寄存器,而如果是i1 1这种常量,就直接输出常量值)。
修改后的代码示例
这里给你调整一下原有的代码片段,实现正确获取实参名称的逻辑:
#include "llvm/IR/CallSite.h" virtual bool runOnFunction(Function &F) { LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); std::string Name = demangle(F.getName()); outs() << "Function " << *(F.getFunctionType()) << " " << Name << " {\n"; for (LoopInfo::iterator i = LI.begin(), e = LI.end(); i != e; ++i) BlocksInLoop(*i, 0); for (Function::iterator b = F.begin(), be = F.end(); b != be; ++b) { for (BasicBlock::iterator i = b->begin(), ie = b->end(); i != ie; ++i) { CallSite CS(&*i); if (!CS) continue; if (CS.getInstruction()->getMetadata("seen")) continue; Function *fct = CS.getCalledFunction(); if (!fct) { // 处理函数指针间接调用的情况,可根据需求扩展逻辑 continue; } outs() << "Call " << *(fct->getFunctionType()) << " " << demangle(fct->getName()) << "\n"; outs() << "Arguments:\n"; // 遍历所有实参(CallSite自动跳过被调用函数的操作数) for (CallSite::arg_iterator argIt = CS.arg_begin(), argEnd = CS.arg_end(); argIt != argEnd; ++argIt) { Value *Arg = *argIt; outs() << " "; // 输出实参类型 Arg->getType()->print(outs()); outs() << " "; if (auto *GV = dyn_cast<GlobalValue>(Arg)) { // 全局变量/函数,输出符号名 outs() << "@" << GV->getName(); } else if (auto *Inst = dyn_cast<Instruction>(Arg)) { // 寄存器类型实参,输出名字(若存在) if (!Inst->getName().empty()) { outs() << "%" << Inst->getName(); } else { // 无名字时,LLVM会自动显示为%<编号>,直接打印Value即可 Arg->print(outs()); } } else if (Arg->isConstant()) { // 常量类型实参,直接输出值 Arg->print(outs()); } else { // 其他类型Value,直接打印 Arg->print(outs()); } outs() << "\n"; } } } outs() << "}\n"; return false; }
补充说明
- 你看到的
.ll文件里的nonnull是实参的属性,可以用CS.getArgAttributes(argIdx)来获取并打印这些属性; - 用
CallSite可以统一处理CallInst和InvokeInst,避免重复写判断逻辑; - 对于无名字的寄存器值,直接调用
Value::print(outs())就能得到和.ll文件一致的%N格式输出。
内容的提问来源于stack exchange,提问作者guillau4
相关产品推荐
相关产品推荐

