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

shi*_*ing 79 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: ...
Run Code Online (Sandbox Code Playgroud)

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

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

Joh*_*itb 109

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();
}
Run Code Online (Sandbox Code Playgroud)

然后

$ clang++ -S -emit-llvm main1.cpp -o - | opt -analyze -dot-callgraph
$ dot -Tpng -ocallgraph.png callgraph.dot
Run Code Online (Sandbox Code Playgroud)

产生一些闪亮的图片(有一个"外部节点",因为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    
Run Code Online (Sandbox Code Playgroud)

产生这种美丽(哦,我的,没有优化的尺寸太大了!)

美女

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

  • 你在多文件项目上做过这个吗?作为一种工具看起来非常酷 (22认同)
  • +1出于某种原因,我必须将-n选项传递给c ++ filt,以便取消名称.以为我会在这里提到它以防其他人面临同样的问题. (2认同)
  • 找到它:我出于某种原因必须删除`-analyze`选项.另一个问:我可以将输出文件名设置为`./ callgraph.dot`以外的其他文件吗? (2认同)
  • 我有第二个问题,如何对不同目录中的多个文件运行此命令? (2认同)

jpo*_*o38 15

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

在此输入图像描述

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

在此输入图像描述

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

  • 您能否添加一个示例,说明如何运行 doxygen 来获取您包含的窗口? (2认同)
  • 我不知道它来自 doxywizard。谢谢! (2认同)

Ira*_*ter 6

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

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

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

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


小智 5

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

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

在此输入图像描述