94

我正在尝试生成调用图,用它来找出所有可能的执行路径,这些路径是命中特定函数的(这样我就不必手动找出所有路径,因为有很多路径导致这个函数)。例如:

path 1: A -> B -> C -> D  
path 2: A -> B -> X -> Y -> D  
path 3: A -> G -> M -> N -> O -> P -> S -> D  
...  
path n: ...

我试过 Codeviz 和 Doxygen,不知何故,这两个结果都只显示目标函数 D 的被调用者。在我的例子中,D 是一个类的成员函数,其对象将被包装在一个智能指针中。客户端将始终通过工厂获取智能指针对象,以便调用 D。

有谁知道如何实现这一目标?

4

8 回答 8

131
static void D() { }
static void Y() { D(); }
static void X() { Y(); }
static void C() { D(); X(); }
static void B() { C(); }
static void S() { D(); }
static void P() { S(); }
static void O() { P(); }
static void N() { O(); }
static void M() { N(); }
static void G() { M(); }
static void A() { B(); G(); }

int main() {
  A();
}

然后

$ clang++ -S -emit-llvm main1.cpp -o - | opt -analyze -dot-callgraph
$ dot -Tpng -ocallgraph.png callgraph.dot

产生一些闪亮的图片(有一个“外部节点”,因为main有外部链接,也可能从该翻译单元外部调用):

调用图

您可能希望使用 对其进行后处理c++filt,以便获得所涉及的函数和类的未损坏名称。像下面这样

#include <vector>

struct A { 
  A(int);
  void f(); // not defined, prevents inlining it!
};

int main() {
  std::vector<A> v;
  v.push_back(42);
  v[0].f();
}

$ clang++ -S -emit-llvm main1.cpp -o - |
   opt -analyze -std-link-opts -dot-callgraph
$ cat callgraph.dot | 
   c++filt | 
   sed 's,>,\\>,g; s,-\\>,->,g; s,<,\\<,g' | 
   gawk '/external node/{id=$1} $1 != id' | 
   dot -Tpng -ocallgraph.png    

产生这种美感(哦,天哪,没有打开优化的尺寸太大了!)

美丽

那个神秘的未命名函数 ,Node0x884c4e0是一个占位符,假定由定义未知的任何函数调用。

于 2011-03-21T04:30:12.303 回答
18

您可以通过使用 doxygen 来实现这一点(可以选择使用 dot 进行图形生成)。

在此处输入图像描述

使用 Johannes Schaub - litb main.cpp,它会生成:

在此处输入图像描述

doxygen/dot 可能比 clang/opt 更容易安装和运行。我没有设法自己安装它,这就是我试图找到替代解决方案的原因!

于 2015-12-03T10:28:27.830 回答
11

静态计算准确的 C++ 调用图很困难,因为您需要一个精确的语言解析器、正确的名称查找以及一个能够正确尊重语言语义的良好指向分析器。Doxygen 没有这些,我不知道为什么人们声称喜欢它用于 C++;很容易构造一个 Doxygen 错误分析的 10 行 C++ 示例)。

您最好运行一个时序分析器,它动态地收集调用图(这描述了我们的)并简单地练习很多案例。此类分析器将向您显示实际执行的调用图。

编辑:我突然想起 了对 C++ 的理解,它声称可以构造调用图。我不知道他们使用什么解析器,也不知道他们是否正确地进行了详细分析;我对他们的产品没有什么特别的经验。我的几次遭遇表明它不做指向分析。

Schaub 使用 Clang 的回答给我留下了深刻的印象;我希望 Clang 拥有正确的所有元素。

于 2011-03-21T04:30:31.150 回答
5

您可以使用CppDepend,它可以生成多种图形

  • 依赖图
  • 调用图
  • 类继承图
  • 耦合图
  • 路径图
  • 所有路径图
  • 循环图

在此处输入图像描述

于 2018-02-06T08:38:58.413 回答
3

为了让clang++命令找到标准头文件,mpi.h应该使用两个附加选项-### -fsyntax-only,即完整的命令应该如下所示:

clang++ -### -fsyntax-only -S -emit-llvm main1.cpp -o - | opt -analyze -dot-callgraph
于 2014-07-03T14:09:32.633 回答
1

“C++ Bsc Analyzer”可以显示调用图 - 通过读取 bscmake 实用程序生成的文件。

于 2014-09-24T20:32:30.887 回答
0

Scitools 理解是一个很棒的工具,比我所知道的所有逆向工程都要好,并且可以生成高质量的图表

但请注意,它非常昂贵,并且试用版的蝶形调用图仅限于一级调用(恕我直言,我相信他们不会帮助自己这样做......)

于 2019-05-21T17:25:16.270 回答
0

当我们想生成调用图时, doxygen + graphviz可以解决大多数问题,然后交给人力。

于 2018-09-17T10:53:29.207 回答