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

问题描述 投票:0回答:9

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

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: ...

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

我怎样才能实现这个目标?

c++ static-analysis call-graph
9个回答
142
投票
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
具有外部链接,也可能从该翻译单元外部调用):

Callgraph

您可能需要使用

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    

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

Beauty

那个神秘的未命名函数,

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


19
投票

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

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

doxygen/dot 可能比 clang/opt 更容易安装和运行。我自己没能安装它,这就是为什么我试图寻找替代解决方案!


12
投票

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

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

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

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


7
投票

你可以使用CppDepend,它可以生成多种图表

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


4
投票

为了让

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

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

1
投票

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


0
投票

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


0
投票

Scitools Understanding 是一个神奇工具,比我所知道的所有逆向工程都要好,并且生成高质量的图表

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


0
投票

GNU cflow

cflow --tree --number main.c a.c b.c

它生成文本风格的调用图,并支持多个文件。

© www.soinside.com 2019 - 2024. All rights reserved.