我有一个很大的工作空间,有许多C代码的源文件.虽然我可以使用Object浏览器看到从MS VS2005中的函数调用的函数,但是在MSVC 6.0中,这只显示了在非图形显示中从特定函数调用的函数.另外,它没有显示从say开始调用的函数main()
,然后是从它调用的函数,依此类推,更深入到叶级函数内部.
我需要一个工具,它会给我一个功能调用图,用图形表示功能callee
,caller
用箭头或类似的东西连接,从main()
最后一级功能开始,或者至少在一个C源文件中以图形方式显示所有功能的调用图.如果我能打印这张图表会很棒.
任何好的工具(不一定是免费的工具)?
埃及(免费软件)
NCC
KcacheGrind(GPL)
Graphviz(CPL)
CodeViz(GPL)
动态分析方法
在这里,我将介绍一些动态分析方法.
动态方法实际运行程序以确定调用图.
与动态方法相反的是静态方法,它试图在不运行程序的情况下单独从源中确定它.
动态方法的优点:
捕获函数指针和虚拟C++调用.这些在任何非平凡的软件中都有大量存在.
动态方法的缺点:
你必须运行程序,这可能很慢,或者需要你没有的设置,例如交叉编译
只显示实际调用的函数.例如,根据命令行参数,可以调用或不调用某些函数.
KcacheGrind
https://kcachegrind.github.io/html/Home.html
测试程序:
int f2(int i) { return i + 2; } int f1(int i) { return f2(2) + i + 1; } int f0(int i) { return f1(1) + f2(2); } int pointed(int i) { return i; } int not_called(int i) { return 0; } int main(int argc, char **argv) { int (*f)(int); f0(1); f1(1); f = pointed; if (argc == 1) f(1); if (argc == 2) not_called(1); return 0; }
用法:
sudo apt-get install -y kcachegrind valgrind # Compile the program as usual, no special flags. gcc -ggdb3 -O0 -o main -std=c99 main.c # Generate a callgrind.out.file. valgrind --tool=callgrind ./main # Open a GUI tool to visualize callgrind data. kcachegrind callgrind.out.1234
您现在处于一个非常棒的GUI程序中,其中包含许多有趣的性能数据.
在右下角,选择"调用图"选项卡.这会显示一个交互式调用图,当您单击这些函数时,它会与其他窗口中的性能指标相关联.
要导出图形,请右键单击它并选择"导出图形".导出的PNG如下所示:
从那我们可以看出:
根节点是_start
实际的ELF入口点,并包含glibc初始化样板
f0
,f1
并按照f2
彼此的预期进行调用
pointed
也显示了,即使我们用函数指针调用它.如果我们传递了命令行参数,它可能没有被调用.
not_called
未显示,因为它没有在运行中被调用,因为我们没有传递额外的命令行参数.
很酷的valgrind
是它不需要任何特殊的编译选项.
因此,即使您没有源代码,也只能使用可执行文件,您可以使用它.
valgrind
通过轻量级"虚拟机"运行代码,设法做到这一点.
在Ubuntu 18.04上测试过.
gcc -finstrument-functions
+ etrace
https://github.com/elcritch/etrace
-finstrument-functions
添加回调,etrace解析ELF文件并实现所有回调.
不幸的是,我无法让它工作:为什么`-finstrument-functions`对我不起作用?
声明的输出格式为:
\-- main | \-- Crumble_make_apple_crumble | | \-- Crumble_buy_stuff | | | \-- Crumble_buy | | | \-- Crumble_buy | | | \-- Crumble_buy | | | \-- Crumble_buy | | | \-- Crumble_buy | | \-- Crumble_prepare_apples | | | \-- Crumble_skin_and_dice | | \-- Crumble_mix | | \-- Crumble_finalize | | | \-- Crumble_put | | | \-- Crumble_put | | \-- Crumble_cook | | | \-- Crumble_put | | | \-- Crumble_bake
除了特定的硬件跟踪支持之外,它可能是最有效的方法,但是您必须重新编译代码.
理解在创建调用图方面做得非常好.
我们的DMS软件再造工具包具有静态控制/数据流/点对/调用图分析,已应用于大型系统(~~ 2500万行)的C代码,并生成此类调用图,包括通过函数指针调用的函数.
您可以尝试使用CScope + tceetree + Graphviz.
你可以在这里查看我的基于bash的C调用树生成器.它允许您指定一个或多个您想要调用者和/或被调用信息的C函数,或者您可以指定一组函数并确定连接它们的函数调用的可达性图...即告诉我所有方式main( ),foo()和bar()是连接的.它使用graphviz/dot作为图形引擎.