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


107

我的工作空间很大,其中包含许多C代码的源文件。尽管可以使用对象浏览器在MS VS2005中看到从函数调用的函数,在MSVC 6.0中也可以看到,但是这仅以非图形形式显示从特定函数调用的函数。此外,它没有显示从say调用的函数main(),然后是从其中调用的函数,依此类推,直到更深入到叶级别函数为止。

我需要一个工具,该工具将以图形方式给我一个函数调用图,calleecaller通过箭头或类似方式将其连接,从main()功能的最后一级开始,或者至少以图形方式在一个C源文件中显示所有函数的调用图。如果可以打印此图,那就太好了。

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


Answers:



29

动态分析方法

在这里,我描述了一些动态分析方法。

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

与动态方法相反的是静态方法,它们试图仅从源代码中确定它而不运行程序。

动态方法的优点:

  • 捕获函数指针和虚拟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.<PID> file.
valgrind --tool=callgrind ./main

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

现在,您将留在一个很棒的GUI程序中,该程序包含许多有趣的性能数据。

在右下方,选择“调用图”标签。这显示了一个交互式调用图,当您单击功能时,该调用图与其他窗口中的性能指标相关。

要导出图形,请右键单击它,然后选择“导出图形”。导出的PNG如下所示:

从中我们可以看到:

  • 根节点是_start,这是实际的ELF入口点,并且包含glibc初始化样板
  • f0f1并且f2彼此之间被称为
  • pointed即使我们使用函数指针调用它,也显示了。如果我们传递了命令行参数,则可能尚未调用它。
  • not_called 之所以没有显示,是因为在运行中没有调用它,因为我们没有传递额外的命令行参数。

有趣的valgrind是,它不需要任何特殊的编译选项。

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

valgrind通过在轻量级的“虚拟机”中运行代码来做到这一点。与本地执行相比,这也使执行极其缓慢。

从图中可以看出,还获得了有关每个函数调用的时序信息,并且可以将其用于配置程序,这很可能是此设置的原始用例,而不仅仅是查看调用图:我如何配置在Linux上运行的C ++代码?

在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

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


2
请注意,动态调用图仅涵盖该程序的一次运行。
smwikipedia 18/09/30

1
@smwikipedia是的,我已经升级了答案,以使内容更清楚
Ciro Santilli郝海东冠状病六四事件法轮功



9

我们的DMS软件再造工具包具有静态控制/数据流/指向/调用图分析,该分析已应用于庞大的C代码系统(约2500万行),并生成了此类调用图,包括通过函数指针调用的函数


1
啊,很好,它出现在2016年,现在出现了降级者。我确信他的反对意见是基于对该工具无法做到的准确评估。好吧,也许不是。它肯定会执行OP的要求。
Ira Baxter

1
投票反对。我不在乎它是你的软件或只要专有的,因为它干得不错:-)
西罗桑蒂利郝海东冠状病六四事件法轮功


5

您可以在此处查看基于bash的C调用树生成器。它使您可以指定一个或多个要为其调用方和/或被调用方信息的C函数,或者可以指定一组函数并确定连接它们的函数调用的可达性图。例如,告诉我main( ),foo()和bar()已连接。它使用graphviz / dot作为绘图引擎。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.