Function *fun = call->getCalledFunction();
如果是间接调用,则getCalledFunction();
返回null。我如何才能获得函数的名称或指针的名称?
我在Stack Overflow中发现了所有与这个问题相关的问题,都在谈论直接调用的函数名,或者指针的类型。
我只想跟踪像这样的案例:
void foo(){}
void goo(){}
void main(){
int x = 1;
void (*p)();
if(x)
p = &foo;
else
p = &goo;
p(); // print the called function name
}
发布于 2015-07-15 08:52:02
我也有同样的问题。下面是我在阅读llvm源代码后的解决方案:
Function* fp = CI->getCalledFunction();
if (fp==NULL) {
Value* v=CI->getCalledValue();
Value* sv = v->stripPointerCasts();
StringRef fname = sv->getName();
errs()<<fname<<"\n";
}
发布于 2015-02-22 23:42:26
我的建议是使用clang AST访问器,而不是使用LLVM IR。
下面是一个AST访问者的例子:
http://clang.llvm.org/docs/RAVFrontendAction.html
如果我们转储代码的AST (编译为C++ -在C中它会有细微的不同,因为func()
的声明与func(...)
相同):
$ clang++ -Xclang -ast-dump -fno-color-diagnostics -c funcptr.cpp
TranslationUnitDecl 0x50973b0 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x50978f0 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
|-TypedefDecl 0x5097950 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
|-TypedefDecl 0x5097d50 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list '__va_list_tag [1]'
|-FunctionDecl 0x5097df0 <funcptr.cpp:1:1, col:12> col:6 used foo 'void (void)'
| `-CompoundStmt 0x5097e90 <col:11, col:12>
|-FunctionDecl 0x5097ed0 <line:2:1, col:12> col:6 used goo 'void (void)'
| `-CompoundStmt 0x5097f70 <col:11, col:12>
`-FunctionDecl 0x5097fe0 <line:3:1, line:14:1> line:3:5 main 'int (void)'
`-CompoundStmt 0x50d98b0 <col:11, line:14:1>
|-DeclStmt 0x50d9548 <line:5:1, col:9>
| `-VarDecl 0x50d94d0 <col:1, col:8> col:5 used x 'int' cinit
| `-IntegerLiteral 0x50d9528 <col:8> 'int' 1
|-DeclStmt 0x50d9678 <line:6:1, col:12>
| `-VarDecl 0x50d9620 <col:1, col:11> col:8 used p 'void (*)(void)'
|-IfStmt 0x50d9818 <line:7:1, line:10:7>
| |-<<<NULL>>>
| |-ImplicitCastExpr 0x50d96d0 <line:7:4> '_Bool' <IntegralToBoolean>
| | `-ImplicitCastExpr 0x50d96b8 <col:4> 'int' <LValueToRValue>
| | `-DeclRefExpr 0x50d9690 <col:4> 'int' lvalue Var 0x50d94d0 'x' 'int'
| |-BinaryOperator 0x50d9758 <line:8:2, col:7> 'void (*)(void)' lvalue '='
| | |-DeclRefExpr 0x50d96e8 <col:2> 'void (*)(void)' lvalue Var 0x50d9620 'p' 'void (*)(void)'
| | `-UnaryOperator 0x50d9738 <col:6, col:7> 'void (*)(void)' prefix '&'
| | `-DeclRefExpr 0x50d9710 <col:7> 'void (void)' lvalue Function 0x5097df0 'foo' 'void (void)'
| `-BinaryOperator 0x50d97f0 <line:10:2, col:7> 'void (*)(void)' lvalue '='
| |-DeclRefExpr 0x50d9780 <col:2> 'void (*)(void)' lvalue Var 0x50d9620 'p' 'void (*)(void)'
| `-UnaryOperator 0x50d97d0 <col:6, col:7> 'void (*)(void)' prefix '&'
| `-DeclRefExpr 0x50d97a8 <col:7> 'void (void)' lvalue Function 0x5097ed0 'goo' 'void (void)'
`-CallExpr 0x50d9888 <line:12:1, col:3> 'void'
`-ImplicitCastExpr 0x50d9870 <col:1> 'void (*)(void)' <LValueToRValue>
`-DeclRefExpr 0x50d9848 <col:1> 'void (*)(void)' lvalue Var 0x50d9620 'p' 'void (*)(void)'
在这里,我们可以很容易地看到,我们正在通过CallExpr
-> ImplicitCastExpr
-> DeclRefExpr
调用p
。这样你就得到了p
。但当然,您必须解释导致p
赋值的代码-这在本例中并不太难,但是假设x
没有被赋值一个常量,那么除了“根据x
的值,它可能是foo
或goo
”之外,几乎不可能再说其他什么了。回溯到p
的赋值可能还需要一些工作,但应该是可行的。您可以查找函数指针的赋值(通过标识指针,使用getPointeeType
,然后使用isa<FunctionType>
或类似的方法)。
要解析llvm,你必须访问每条指令并找到导致调用的加载-当使用优化时,这是反过来完成的,通过用p = &foo;
替换if (x) p = &foo; else p = &goo;
,然后意识到p
总是设置为单个值,所以在这个简单的例子中不需要通过函数指针调用。但LLVM IR本身并不跟踪数据的实际来源。一般来说,这是一个类似的原则,只是你离源代码更远了,并且将不得不执行更多的步骤来找出被调用者是什么。
起始点将是一个函数或模块传递,这将在LLVM文档的这一节中进行描述。
http://llvm.org/docs/WritingAnLLVMPass.html
我还没有看过所有的细节,但我想说CallGraphSCCPass
可能是一个很好的起点,因为它从Callee开始,您可以在调用图中向上工作,而不是向下。但可能不适合这种特殊的情况,因为所有的事情都发生在一个函数中--不确定。
正如我在注释中所说的,对于微不足道的情况,这是可以做到的,但祝您好运,尝试遵循任何依赖于用户数据或编译时不可确定的函数(当然,如果函数的结果是编译时可确定的,则它是编译时可确定的;如果已知源代码和所有影响输出的输入,则它是编译时可确定的!)
发布于 2016-10-16 07:42:36
忘了它吧:这是不可能的。这需要完美的别名分析。如果可能,LLVM将删除间接调用作为优化。
您提到的情况很简单:优化后的LLVM会将其转换为直接调用,您可以直接获取函数。
如果x
是一个全局变量,您可能能够获得一个函数名列表(这里是foo和goo),但不知道实际调用的是哪一个。但即便如此,LLVM也应该能够进行选择性的间接调用提升并公开直接调用。
https://stackoverflow.com/questions/28653072
复制相似问题