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


87

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

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

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

답변:


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


24
다중 파일 프로젝트에서이 작업을 수행 했습니까? 외모는 매우 도구로 냉각
dirvine

2
+1 어떤 이유로 이름을 풀기 위해 -n 옵션을 c ++ filt에 전달해야했습니다. 다른 사람이 같은 문제에 직면 할 경우를 대비하여 여기서 언급 할 것이라고 생각했습니다.
Aky

1
이 작업을 시도 할 때 오류가 발생합니다. Pass::print not implemented for pass: 'Print call graph to 'dot' file'!무슨 일입니까? clang 3.8
Arne

2
찾았습니다 : -analyze어떤 이유로 든 옵션 을 제거해야합니다 . 또 다른 질문 : 출력 파일 이름을 다른 이름으로 설정할 수 ./callgraph.dot있습니까?
Arne

2
두 번째 질문은 다른 디렉토리에있는 여러 파일에 대해이 명령을 실행하는 방법입니다.
Newbie

18

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

여기에 이미지 설명 입력

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

여기에 이미지 설명 입력

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


1
포함 된 창을 얻기 위해 doxygen을 실행하는 방법의 예를 추가 할 수 있습니까?
nimble_ninja

@nimble_ninja : doxywizard 구성 대화 상자의 스크린 샷이 충분하지 않습니까?
jpo38

1
나는 그것이 doxywizard로부터 온 것인지 몰랐다. 감사!
nimble_ninja 2017 년

1
최고의 방법! :)
Leslie N

대규모 프로젝트에서는 실제로 실행 가능하지 않고 24 시간 동안 실행 된 기가 바이트의 HTML 문서이지만 아직 완료되지 않았습니다. 몇 가지 특정 함수 (main () <=> SQL_COMMIT () 간의 완전한 트리)에 대한 호출 그래프가 필요합니다.
Gizmo

9

정확한 C ++ 호출 그래프를 정적으로 계산하는 것은 어렵습니다. 정확한 언어 파서, 정확한 이름 조회 및 언어 의미 체계를 올바르게 준수하는 좋은 포인트 투 분석기가 필요하기 때문입니다. Doxygen에는 이러한 것들이 없습니다. 왜 사람들이 C ++를 좋아한다고 주장하는지 모르겠습니다. Doxygen이 잘못 분석하는 10 줄 C ++ 예제를 쉽게 구성 할 수 있습니다.)

호출 그래프를 동적으로 수집하고 (이것은 우리의 것을 설명 함) 단순히 많은 경우를 실행하는 타이밍 프로파일 러를 실행하는 것이 더 나을 수 있습니다 . 이러한 프로파일 러는 실행 된 실제 콜 그래프를 보여줍니다.

편집 : 갑자기 콜 그래프를 구성한다고 주장하는 C ++ 이해를 기억했습니다 . 나는 그들이 파서에 무엇을 사용하는지 또는 그들이 상세한 분석을 제대로하는지 여부를 모릅니다. 나는 그들의 제품에 대한 특별한 경험이 없습니다.

Clang을 사용한 Schaub의 답변에 감명을 받았습니다. 나는 Clang이 모든 요소를 ​​올바르게 갖기를 기대합니다.


불행히도 그 함수를 트리거 할 수있는 모든 사용 사례를 알지 못합니다 :(. 사실 내 궁극적 인 목표는 디버깅 목적으로 해당 함수를 활용하는 사용 사례의 정확한 목록을 찾는 것입니다. 나는 알아낼 수 있습니다. 코드 인덱싱 도구를 사용하는 직접 호출자이지만 추가 분석을 위해 모든 실행 경로를 파악해야합니다.
shiouming 2011 년

그래서 정말로 원하는 것은 메소드가 호출되는 실행 조건입니까? 그런 다음 원하는 메서드를 만날 때까지 조건식을 수집하여 호출 그래프의 다양한 노드에서 제어 흐름을 따라 걸을 수있는 완전하고 정확한 호출 그래프와 도구의 능력이 필요합니다. 나는 이것을 할 기성품 도구에 대해 모른다. (이 의견은 질문보다 7 년 늦었다.) 이를 수행하려면 사용자 정의 분석 엔진이 필요할 것입니다. Clang이 여기에 눌려 질 수 있습니다. 이를 위해 DMS 툴킷을 사용할 수 있습니다.
Ira Baxter

5

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

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.