web-dev-qa-db-ja.com

コードの画像関数呼び出しグラフを取得するツール

Cコードの多くのソースファイルがある大きなワークスペースがあります。 MS VS2005の関数から呼び出された関数はオブジェクトブラウザーを使用して確認できますが、MSVC 6.0でも、これは特定の関数から呼び出された関数のみを非グラフィカルな種類のディスプレイに表示します。また、たとえばmain()から開始して呼び出される関数、およびそれから呼び出される関数などは、リーフレベル関数のより深い内部には表示されません。

関数calleecallerが矢印などで接続され、main()から最後のレベルまでの関数呼び出しグラフを絵で表示するツールが必要です。関数、または少なくとも1つのCソースファイル内のすべての関数の呼び出しグラフを絵で表示します。このグラフを印刷できたら素晴らしいと思います。

それを行うための良いツールはありますか(無料のツールである必要はありません)?

102
goldenmean
49
philant

動的解析方法

ここでは、いくつかの動的解析方法について説明します。

動的メソッドは、実際にプログラムを実行して呼び出しグラフを決定します。

動的メソッドの反対は静的メソッドです。静的メソッドは、プログラムを実行せずにソースのみから決定しようとします。

動的な方法の利点:

  • 関数ポインターと仮想C++呼び出しをキャッチします。これらは、重要なソフトウェアに多数存在します。

動的メソッドの欠点:

  • プログラムを実行する必要がありますが、実行に時間がかかるか、持っていないセットアップが必要です。クロスコンパイル
  • 実際に呼び出された関数のみが表示されます。たとえば、一部の関数は、コマンドライン引数に応じて呼び出される場合と呼び出されない場合があります。

KcacheGrind

https://kcachegrind.github.io/html/Home.html

テストプログラム:

int f2(int i) { return i + 2; }
int f1(int i) { return f2(2) + i + 1; }
int f0(int i) { return f1(1) + f2(2); }
int pointed(int i) { return i; }
int not_called(int i) { return 0; }

int main(int argc, char **argv) {
    int (*f)(int);
    f0(1);
    f1(1);
    f = pointed;
    if (argc == 1)
        f(1);
    if (argc == 2)
        not_called(1);
    return 0;
}

使用法:

Sudo apt-get install -y kcachegrind valgrind

# Compile the program as usual, no special flags.
gcc -ggdb3 -O0 -o main -std=c99 main.c

# Generate a callgrind.out.<PID> file.
valgrind --tool=callgrind ./main

# Open a GUI tool to visualize callgrind data.
kcachegrind callgrind.out.1234

これで、多くの興味深いパフォーマンスデータが含まれる素晴らしいGUIプログラムの内部に残ります。

右下で、「コールグラフ」タブを選択します。これは、関数をクリックすると、他のウィンドウのパフォーマンスメトリックと相関するインタラクティブな呼び出しグラフを示します。

グラフをエクスポートするには、グラフを右クリックして、「グラフのエクスポート」を選択します。エクスポートされたPNGは次のようになります。

それから次のことがわかります。

  • ルートノードは_startは、実際のELFエントリポイントであり、glibc初期化ボイラープレートが含まれています
  • f0f1およびf2は互いに期待どおりに呼び出されます
  • 関数ポインターで呼び出した場合でも、pointedも表示されます。コマンドライン引数を渡した場合は、呼び出されていない可能性があります。
  • not_calledは、追加のコマンドライン引数を渡さなかったため、実行時に呼び出されなかったため表示されません。

valgrindの素晴らしい点は、特別なコンパイルオプションを必要としないことです。

そのため、ソースコードがなくても実行可能ファイルのみを使用できます。

valgrindは、軽量の「仮想マシン」を介してコードを実行することにより、それを管理しています。

Ubuntu 18.04でテスト済み。

gcc -finstrument-functions + etrace

https://github.com/elcritch/etrace

-finstrument-functionsコールバックを追加 、etraceはELFファイルを解析し、すべてのコールバックを実装します。

しかし、残念ながら動作させることができませんでした: 「-finstrument-functions」が機能しないのはなぜですか?

要求された出力は次の形式です。

\-- main
|   \-- Crumble_make_Apple_crumble
|   |   \-- Crumble_buy_stuff
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   \-- Crumble_prepare_apples
|   |   |   \-- Crumble_skin_and_dice
|   |   \-- Crumble_mix
|   |   \-- Crumble_finalize
|   |   |   \-- Crumble_put
|   |   |   \-- Crumble_put
|   |   \-- Crumble_cook
|   |   |   \-- Crumble_put
|   |   |   \-- Crumble_bake

特定のハードウェアトレースサポートに加えて最も効率的な方法と思われますが、コードを再コンパイルする必要があるという欠点があります。

nderstand は、コールグラフの作成に非常に適しています。

17
MattK

DMS Software Reengineering Toolkit には static control/dataflow/points-to/call graph analysis があり、Cコードの巨大なシステム(〜2,500万行)に適用されています。そして、そのようなコールグラフを生成しました、関数ポインタを介して呼び出された関数を含みます

8
Ira Baxter

CScope + tceetree + Graphviz を試すことができます。

6
Fabio Visona'

BashベースのC呼び出しツリージェネレーター here を確認できます。呼び出し元や呼び出し先の情報が必要な1つ以上のC関数を指定できます。または、関数のセットを指定して、それらを接続する関数呼び出しの到達可能性グラフを決定できます。 main()、foo()、およびbar()が接続されるすべての方法を教えてください。グラフ作成エンジンにgraphviz/dotを使用します。

5
Jason Nyberg

Astrée は、最も堅牢で洗練されたツールです。

3
ЯegDwight