获取图形化函数的工具调用代码图形

我有一个大的工作空间,其中有许多 C 代码的源文件。虽然我可以在 MS VS2005中看到使用 Object 浏览器从函数调用的函数,在 MSVC 6.0中也可以看到,但是这只能在非图形化的显示中显示从特定函数调用的函数。此外,它没有显示从 main()开始调用的函数,然后是从它调用的函数,以此类推,在叶级函数的更深层次显示。

我需要一个工具,它可以给我一个函数调用图形,其中的函数 calleecaller用箭头或类似的东西连接起来,从 main()到最后一个级别的函数,或者至少在一个 C 源文件中显示所有函数的调用图形。如果我能把这张图打印出来就太好了。

有什么好的工具可以做到这一点(不一定是免费的工具) ?

142081 次浏览

理解 在创建调用图表方面做得非常好。

恕我直言,Astrée 是世界上最强大、最复杂的工具。

我们的 软件再造工具包静态控制/数据流/指向/调用图分析,已经应用于大型系统(约2500万行)的 C 代码,并产生这样的调用图,包括通过函数指针调用的函数

你可以试试 CScope + Tceetree + Graphviz

动态分析方法

这里我将描述一些动态分析方法。

动态方法实际上运行程序来确定调用图。

与动态方法相反的是静态方法,静态方法试图在不运行程序的情况下单独从源中确定它。

动态方法的优点:

  • 捕获函数指针和虚拟 C + + 调用。这些在任何重要的软件中都有大量的存在。

Disadvantages of dynamic methods:

  • 你必须运行程序,这可能会很慢,或者需要一个你没有的设置,例如交叉编译
  • 只有实际调用的函数才会显示。例如,可以根据命令行参数调用或不调用某些函数。

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;
}

Usage:

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.<PID> file.
valgrind --tool=callgrind ./main


# Open a GUI tool to visualize callgrind data.
kcachegrind callgrind.out.1234

现在您已经进入了一个非常棒的 GUI 程序,其中包含了大量有趣的性能数据。

在右下角,选择“调用图表”选项卡。这显示了一个交互式调用图,当您单击这些函数时,它与其他窗口中的性能指标相关联。

要导出图形,右键单击并选择“ Export Graph”。导出的 PNG 如下所示:

从中我们可以看出:

  • 根节点是 _start,它是实际的 ELF 入口点,包含 glibc 初始化样板
  • f0f1f2按预期互相调用
  • 即使我们用函数指针来称呼它,它也显示了 ABc0。如果我们传递了一个命令行参数,它可能就不会被调用。
  • 没有显示 not_called,因为它在运行中没有被调用,因为我们没有传递额外的命令行参数。

valgrind最酷的地方在于它不需要任何特殊的编译选项。

因此,即使没有源代码,只有可执行文件,也可以使用它。

valgrind通过在轻量级“虚拟机”中运行代码来实现这一点。这也使得与本机执行相比,执行速度极其缓慢。

如图所示,还可以获得关于每个函数调用的计时信息,这可以用来分析程序,这可能是此设置的原始用例,而不仅仅是查看调用图: 如何分析在 Linux 上运行的 C + + 代码?

在 Ubuntu 18.04上测试。

gcc -finstrument-functions + 回溯

Https://github.com/elcritch/etrace

-finstrument-functions 增加了回调,etrace 解析 ELF 文件并实现所有回调。

然而不幸的是,我无法让它工作: 为什么不为我工作的 t‘-乐器-功能?

索赔产出的格式如下:

\-- 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

除了特定的硬件跟踪支持之外,这可能是最有效的方法,但是它的缺点是必须重新编译代码。

您可以查看我的基于 bash 的 C 调用树生成器 给你。它允许您指定一个或多个需要调用方和/或调用信息的 C 函数,或者您可以指定一组函数并确定连接它们的函数调用的可达性图... ... 也就是说,告诉我 main ()、 foo ()和 bar ()连接的所有方式。它使用 Graphviz/dot 作为图形引擎。