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

时间:2011-03-21 04:09:40

标签: c++ static-analysis call-graph

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

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。

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

8 个答案:

答案 0 :(得分:104)

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

答案 1 :(得分:13)

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

enter image description here

使用Johannes Schaub - litb main.cpp,它产生了这个:

enter image description here

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

答案 2 :(得分:6)

静态计算准确的C ++调用图很难,因为你需要一个精确的语言解析器,正确的名称查找,以及一个能够正确理解语言语义的优秀分析器。 Doxygen没有这些,我不知道为什么人们声称喜欢C ++;很容易构建Doxygen错误分析的10行C ++示例。

你可能最好不要运行timing profiler which collects a call graph dynamically(这描述了我们的)并且只是运用了很多案例。此类分析器将显示实际调用图表。

编辑:我突然想起Understand for C++,声称构建了呼叫图。我不知道他们使用什么解析器,或者他们是否正确进行详细分析;我对他们的产品没有具体经验。

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

答案 3 :(得分:5)

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

  • 依赖关系图
  • 致电图
  • 类继承图
  • 耦合图
  • 路径图
  • 所有路径图
  • 循环图

enter image description here

答案 4 :(得分:2)

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

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

答案 5 :(得分:1)

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

Scitools Understand是一种奇妙的工具,比我对逆向工程所了解的要好,并且可以生成高质量的图形。< / p>

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