如何为C ++代码生成调用图


87

我正在尝试生成调用图,通过该图可以找到击中特定函数的所有可能执行路径(这样我就不必手动找出所有路径,因为有许多路径可以导致该函数)。例如:

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。

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

Answers:


118
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是一个占位符,被假定由定义未知的任何函数调用。


22
您是否在多文件项目中完成了此任务?作为工具看起来非常酷
dirvine 2012年

2
+1由于某种原因,我必须将-n选项传递给c ++ filt才能使名称解散。以为我在这里提到了它,以防其他人遇到同样的问题。
2014年

1
尝试此操作时出现错误:Pass::print not implemented for pass: 'Print call graph to 'dot' file'!这是怎么回事?clang 3.8
Arne 2015年

2
发现它:-analyze由于某种原因,我必须删除该选项。另一个问:我可以将输出文件名设置为非./callgraph.dot吗?
Arne 2015年

2
我有第二个问题,如何对不同目录中的多个文件运行此命令?
新手

18

您可以通过使用doxygen(带有将点用于生成图形的选项)来实现。

在此处输入图片说明

使用Johannes Schaub-litb main.cpp,它将生成以下内容:

在此处输入图片说明

doxygen / dot可能比clang / opt易于安装和运行。我没有设法自己安装它,这就是为什么我尝试寻找替代解决方案的原因!


1
您能否添加一个示例,说明如何运行doxygen以获取所包含的窗口?
nimble_ninja'3

@nimble_ninja:doxywizard配置对话框中的屏幕截图不够吗?
jpo38

1
我不知道那是多西奇。谢谢!
nimble_ninja

1
有史以来最好的方法!:)
莱斯利

对于大型项目而言,并不是真正可行的,它运行了24H,千兆字节的HTML文档,但仍未完成。我只需要一些特定功能的调用图(到main()<=> SQL_COMMIT()的/从/之间的完整树)。
Gizmo

9

静态计算准确的C ++调用图非常困难,因为您需要一个精确的语言解析器,正确的名称查找以及一个很好的指向分析器,以正确地体现语言的语义。Doxygen没有这些,我不知道为什么人们声称喜欢C ++。很容易构造一个10行的C ++示例(Doxygen错误地对其进行了分析)。

您最好运行一个时序分析器,该分析器可以动态收集调用图(这描述了我们的调用图),并且只需执行很多情况即可。这样的探查器将向您显示实际执行的调用图。

编辑:我突然想起了 了解C ++,它声称可以构造调用图。我不知道它们用于解析器是什么,也不知道它们是否进行了详细的分析?我对他们的产品没有具体经验。

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


不幸的是,我不知道可能触发该功能的所有用例:(。实际上,我的最终目标是找出利用该功能进行调试的用例的确切列表。我能够找出直接调用者使用代码索引工具,但需要找出所有执行路径以进行进一步分析
shiouming 2011年

那么,您真正想要的是在什么条件下调用方法?然后,您需要一个完整,准确的调用图,并需要一种工具的能力来遍历调用图中各个节点中的控制流,收集条件表达式,直到遇到所需的方法为止。我不知道有任何现成的工具可以做到这一点(比问题晚了7年)。您可能需要一个自定义分析引擎来执行此操作。lang可能会被压入其中;我们的DMS工具包可用于此目的。
艾拉·巴克斯特

5

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

  • 依赖图
  • 通话图
  • 类继承图
  • 耦合图
  • 路径图
  • 所有路径图
  • 循环图

在此处输入图片说明


3

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

clang++ -### -fsyntax-only -S -emit-llvm main1.cpp -o - | opt -analyze -dot-callgraph

1

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


0

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


0

Scitools Understand是一个很棒的工具,比我所了解的逆向工程更好,并且可以生成高质量的图形

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

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.