【问题标题】:How to Generate a calling graph for C++ code如何为 C++ 代码生成调用图
【发布时间】:2011-07-19 10:12:29
【问题描述】:

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

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


    【解决方案1】:
    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 是一个占位符,假定被任何定义未知的函数调用。

    【讨论】:

    • 你在多文件项目上做过吗?作为一个工具看起来很酷
    • +1 出于某种原因,我必须将 -n 选项传递给 c++filt 才能解开名称。以为我会在这里提到它,以防其他人面临同样的问题。
    • 我在尝试这个时遇到错误:Pass::print not implemented for pass: 'Print call graph to 'dot' file'! 这是怎么回事?铿锵 3.8
    • 找到它:出于某种原因,我必须删除 -analyze 选项。另一个问:我可以将输出文件名设置为./callgraph.dot以外的其他名称吗?
    • 我的第二个问题,如何对不同目录中的多个文件运行此命令?
    【解决方案2】:

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

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

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

    【讨论】:

    • 您能否添加一个示例,说明如何运行 doxygen 以获取包含的窗口?
    • @nimble_ninja:doxywizard 配置对话框的截图还不够吗?
    • 我不知道它来自 doxywizard。谢谢!
    • 有史以来最好的方法! :)
    • 对于一个大型项目来说并不可行,运行 24 小时,千兆字节的 HTML 文档,仍然没有完成.. 跳过这个。我只需要一些特定函数的调用图(到/从/在 main() SQL_COMMIT() 之间的完整树)。
    【解决方案3】:

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

    您最好运行timing profiler which collects a call graph dynamically(这描述了我们的)并简单地练习很多案例。此类分析器将向您显示实际执行的调用图。

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

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

    【讨论】:

    • 不幸的是,我不知道所有可能触发该功能的用例:(。事实上,我的最终目标是找出使用该功能进行调试的用例的确切列表. 我可以通过代码索引工具找到直接调用者,但需要弄清楚所有执行路径以供进一步分析。
    • 那么你真正想要的是调用方法的执行条件?然后,您需要一个完整、准确的调用图,以及一个工具能够沿着调用图中各个节点中的控制流走,收集条件表达式,直到遇到所需的方法。我不知道有任何现成的工具可以做到这一点(这个评论比问题晚了 7 年);您可能需要一个自定义分析引擎来执行此操作。 Clang可能会被压入其中;我们的 DMS 工具包可以用于此。
    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

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

          【讨论】:

            【解决方案8】:

            Scitools Understand 是一个了不起的工具,比我所知道的所有逆向工程都要好,并且可以生成高质量的图表

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

            【讨论】:

              猜你喜欢
              • 2012-07-25
              • 1970-01-01
              • 2015-12-13
              • 1970-01-01
              • 2011-06-05
              • 2020-07-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多