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を呼び出すために、常にファクトリを介してスマートポインタオブジェクトを取得します。

誰かがこれを達成する方法を知っていますか?

回答:


118
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、定義が不明な関数によって呼び出されると想定されるプレースホルダーです。


22
マルチファイルプロジェクトでこれを実行しましたか?ツールとして非常にクールに見えます
dirvine 2012年

2
+1何らかの理由で、名前をアンマングルするために-nオプションをc ++ filtに渡す必要がありました。他の誰かが同じ問題に直面した場合に備えて、ここで言及したいと思います。
aky 2014年

1
これを試してみるとエラーが発生します:Pass::print not implemented for pass: 'Print call graph to 'dot' file'!どうしたの?clang 3.8
Arne

2
見つかりました:-analyze何らかの理由でオプションを削除する必要があります。別のQ:出力ファイル名を他のものに設定でき./callgraph.dotますか?
アルネ

2
私が持っている2番目の質問は、異なるディレクトリ内の複数のファイルに対してこのコマンドを実行する方法ですか?
初心者2018年

18

これは、doxygenを使用することで実現できます(グラフの生成にドットを使用するオプションがあります)。

ここに画像の説明を入力してください

Johannes Schaub --litb main.cppを使用すると、次のように生成されます。

ここに画像の説明を入力してください

doxygen / dotは、clang / optよりもインストールと実行が簡単です。私はそれを自分でインストールすることができなかったので、別の解決策を見つけようとしました!


1
含めたウィンドウを取得するためにdoxygenを実行する方法の例を追加できますか?
nimble_ninja 2017年

@nimble_ninja:doxywizard構成ダイアログのスクリーンショットでは不十分ですか?
jpo38 2017年

1
それがdoxywizardからのものだとは知りませんでした。ありがとう!
nimble_ninja 2017年

1
史上最高の方法!:)
レスリー

大規模なプロジェクトでは実際には実行可能ではなく、24時間、ギガバイトのHTMLドキュメントで実行されましたが、まだ実行されていません。これをスキップします。いくつかの特定の関数(main()<=> SQL_COMMIT()へ/から/の間の完全なツリー)のコールグラフが必要です。
ギズモ

9

正確な言語パーサー、正しい名前ルックアップ、および言語セマンティクスを適切に尊重する優れたポイントツーアナライザーが必要なため、正確なC ++コールグラフを静的に計算することは困難です。Doxygenにはこれらのどれもありません。なぜ人々がC ++でそれを好きだと主張するのか分かりません。Doxygenが誤って分析する10行のC ++の例を作成するのは簡単です)。

コールグラフを動的に収集するタイミングプロファイラーを実行して(これは私たちのグラフを説明しています)、単純に多くのケースを実行する方がよい場合があります。このようなプロファイラーは、実際に実行されたコールグラフを表示します。

編集:私は突然、コールグラフを作成すると主張するC ++の理解を思い出しました 。彼らがパーサーに何を使用しているか、または詳細な分析を正しく行っているかどうかはわかりません。私は彼らの製品について特別な経験はありません。

Clangを使用したSchaubの答えに感銘を受けました。Clangにはすべての要素が正しいと思います。


残念ながら、私はその関数をトリガーする可能性のあるすべてのユースケースを認識していません:(。実際、私の最終的な目標は、デバッグ目的でその関数を利用するユースケースの正確なリストを見つけることです。私は見つけることができます直接コードインデックス作成ツールで発信者が、さらなる分析のために、すべての実行パスを把握する必要があります。
shiouming

では、本当に必要なのは、メソッドが呼び出される実行条件ですか?次に、完全で正確なコールグラフと、目的のメソッドが見つかるまで、条件式を収集して、コールグラフのさまざまなノードの制御フローに沿って歩くツールの機能が必要です。これを行う既製のツールを私は知りません(このコメントは質問から7年後です)。これを行うには、カスタム分析エンジンが必要になる可能性があります。Clangはこれに押し込まれる可能性があります。これには、DMSツールキットを使用できます。
Ira Baxter

5

CppDependを使用でき、さまざまな種類のグラフを生成できます

  • 依存関係グラフ
  • コールグラフ
  • クラス継承グラフ
  • カップリンググラフ
  • パスグラフ
  • すべてのパスグラフ
  • サイクルグラフ

ここに画像の説明を入力してください


3

clang++コマンドが標準のヘッダーファイルを見つけるには、mpi.h2つの追加オプションを使用する必要があります-### -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は、リバースエンジニアリングで私が知っているすべてのものよりも優れた素晴らしいツールであり、高品質のグラフを生成します。

ただし、非常に高額であり、試用版のバタフライコールグラフは1レベルのコールのみに制限されていることに注意してください(私見では、彼らはそうするのに役立たないと思います…)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.