这个问题与a question I've asked earlier this day有关:我想知道是否有可能从给定的函数(或符号名称,例如从nm
中获取)生成调用者图,即使兴趣不属于“我的”源代码的一部分(例如位于库中,例如malloc()
)
例如,要知道在名为malloc
的程序中foo
的使用位置,我将首先查找符号名称:
nm foo | grep malloc
U malloc@@GLIBC_2.2.5
然后运行一个工具(可能需要我程序的特殊编译/链接版本或某些编译器构件):
find_usages foo-with-debug-symbols "malloc@@GLIBC_2.2.5"
这将生成一个(文本)调用方图,然后可以对其进行进一步处理。
阅读this question时,我发现radare2几乎可以完成您可以想象的所有事情,但是由于某种原因,我还无法从给定的符号中生成调用者图。.
进度
使用radare2
已设法从可执行文件生成dot
调用者图,但是仍然缺少某些内容。我正在编译下面的C ++程序,我确定该程序必须使用malloc()
或new
:
#include <string>
int main() {
auto s = std::string("hello");
s += " welt";
return 0;
}
我使用静态库进行编译,以确保可以在二进制文件中找到我要分析的所有调用:
g++ foo.cpp -static
通过运行nm a.out | grep -E "_Znwm|_Znam|_Znwj|_Znaj|_ZdlPv|_ZdaPv|malloc|free"
,您可以看到很多用于内存分配的符号。
现在,我在可执行文件上运行radare2
:
r2 -qAc 'agCd' a.out > callgraph.dot
用一个小脚本(受this answer启发),我正在寻找包含“ sym.operatornew”的任何符号的调用路径,但似乎没有!
有没有一种方法可以确保从/到任何函数中生成调用图所需的 all 所有信息?
是否有更好的方式运行radare2?看起来不同的调用图可视化类型提供了不同的信息-例如ascii艺术生成器确实提供了点生成器未提供的符号的名称,而点生成器提供了有关调用的更多详细信息。
答案 0 :(得分:1)
通常,由于存在indirect jumps and calls,因此无法从二进制文件中提取 exact 控制流图。机器代码间接调用正在跳入某个寄存器的内容,并且您不能可靠地估计寄存器可以使用的所有值(这样做可以证明等效于halting problem)。 / p>
是否有办法确保从该二进制文件内调用的任何函数生成调用图所需的所有信息?
否,并且该问题等同于暂停问题,因此永远不会有确定的方法来获取该调用图(完整且合理的方式)
(通常)C ++编译器将为虚拟函数调用生成间接跳转(它们通过vtable跳转),并且可能在使用共享库时(请参阅Drepper的How To Write Shared Libraries论文以获取更多信息)。
至少要查找引用,才能使用BINSEC工具(由CEA,LIST和INRIA的同事开发)。
如果您真的想在C ++源代码中找到大多数(但不是全部)动态内存分配,则可以使用静态源代码分析(例如Frama-C或Frama-Clang)和其他工具,但是他们不是银弹。
请记住,可以将诸如malloc
或operator new
之类的分配函数放在函数指针位置(并且您的C ++代码可能在某个地方深埋了allocator,那么您很可能会< em>间接调用malloc
)
也许您可能需要花费数月的时间来编写自己的GCC plugin,以便在GCC编译器内进行优化后寻找对malloc
的调用(但请注意,GCC插件已绑定到特定版本的GCC)。我不确定是否值得付出努力。我的旧的(过时的,未维护的)GCC MELT项目was能够找到对malloc
的调用,该调用的大小大于给定常数。也许至少在2019年底或更晚的一年中,我的后续项目(bismon,由CHARIOT H2020项目资助)可能已经足够成熟,可以为您提供帮助。
还请记住,GCC能够进行与malloc
相关的优化。尝试编译以下C代码
//file mallfree.c
#include <stdlib.h>
int weirdsum(int x, int y) {
int*ar2 = malloc(2*sizeof(int));
ar2[0] = x; ar2[1] = y;
int r = ar2[0] + ar2[1];
free (ar2);
return r;
}
与gcc -S -fverbose-asm -O3 mallfree.c
。您将看到生成的mallfree.s
汇编程序文件不包含对malloc
或free
的调用。 As-if rule允许这种优化,并且对于优化C ++标准containers的大多数用法非常有用。
所以想要的东西不简单 ,即使是显然“简单”的C ++代码(不可能 通常情况下。
如果您要编写GCC插件的代码,并且在该问题上花了整整一年的时间(或为此可能需要支付至少50万欧元),请与我联系。也可以看看 https://xkcd.com/1425/(您的问题实际上是不可能的一个问题)。
顺便说一句,顺便说一句,顺便说一句,您真正关心的是优化后的代码中的动态内存分配(您确实想要inlining和dead code elimination,而GCC在-O3
或-O2
)。当GCC根本没有优化时(例如,使用-O0
是隐式优化),它将进行很多“无用的”动态内存分配,特别是对于C ++代码(使用C ++标准库)。另请参阅CppCon 2017:Matt Godbolt “最近我的编译器为我做了什么?取消编译器的盖子”。 talk。