development

C ++ 코드에 대한 호출 그래프를 생성하는 방법

big-blog 2020. 10. 12. 07:49
반응형

C ++ 코드에 대한 호출 그래프를 생성하는 방법


특정 함수에 도달하는 가능한 모든 실행 경로를 찾을 수있는 호출 그래프를 생성하려고합니다 (이 함수로 이어지는 경로가 많기 때문에 수동으로 모든 경로를 파악할 필요가 없습니다.) ). 예를 들면 :

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를 호출하기 위해 항상 팩토리를 통해 스마트 포인터 개체를 얻습니다.

누구든지 이것을 달성하는 방법을 알고 있습니까?


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는 정의를 알 수없는 함수에 의해 호출되는 것으로 간주되는 자리 표시 자입니다.


doxygen (그래프 생성에 점을 사용하는 옵션 포함)을 사용하여이를 달성 할 수 있습니다.

여기에 이미지 설명 입력

Johannes Schaub-litb main.cpp를 사용하여 다음을 생성합니다.

여기에 이미지 설명 입력

doxygen / dot는 clang / opt보다 설치하고 실행하는 것보다 쉬울 것입니다. 내가 직접 설치하지 못했기 때문에 대체 솔루션을 찾으려고 노력했습니다!


Statically computing an accurate C++ call graph is hard, because you need a precise langauge parser, correct name lookup, and a good points-to analyzer that honors the language semantics properly. Doxygen doesn't have any of these, I don't know why people claim to like it for C++; it is easy to construct a 10 line C++ example that Doxygen erroneously analyzes).

You might be better off running a timing profiler which collects a call graph dynamically (this describes ours) and simply exercise a lot of cases. Such profilers will show you the actual call graph exercised.

EDIT: I suddenly remembered Understand for C++, which claims to construct call graphs. I don't know what they use for a parser, or whether they do the detailed analysis right; I have no specific experience with their product.

I am impressed by Schaub's answer, using Clang; I would expect Clang to have all the elements right.


You can use CppDepend, it can generates many kinds of graphs

  • Dependency Graph
  • Call Graph
  • Class Inheritance Graph
  • Coupling Graph
  • Path Graph
  • All Paths Graph
  • Cycle Graph

여기에 이미지 설명 입력


In order for the clang++ command to find standard header files like mpi.h two additional options should be used -### -fsyntax-only, i.e. the full command should look as:

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

The "C++ Bsc Analyzer" can display call graphs - by reading the file generated by the bscmake utility.


doxygen + graphviz 는 콜 그래프를 생성하고 싶을 때 대부분의 문제를 해결할 수 있습니다.


Scitools Understand내가 리버스 엔지니어링에 대해 아는 모든 것보다 뛰어난 환상적인 도구이며 고품질 그래프를 생성 합니다 .

그러나 그것은 매우 비싸고 평가판에는 나비 호출 그래프가 한 수준의 호출로만 제한되어 있다는 점에 유의하십시오 (IMHO 나는 그들이 그렇게하는 데 도움이되지 않는다고 생각합니다 ...)

참고 URL : https://stackoverflow.com/questions/5373714/how-to-generate-a-calling-graph-for-c-code

반응형