如何为 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: ...

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

有谁知道如何做到这一点?

c++ static-analysis call-graph
9个回答
141
投票
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++ 示例很容易)。

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

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

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


7
投票

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

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


3
投票

为了让

clang++
命令找到像
mpi.h
这样的标准头文件,应该使用两个额外的选项
-### -fsyntax-only
,即完整的命令应该看起来像:

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

1
投票

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


0
投票

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


0
投票

Scitools Understand 是一个 fantastic 工具,比我所知道的一切都好逆向工程,并生成高质量的图表

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


0
投票

GNU 流程

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

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

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