113

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

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

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

4

7 に答える 7

61
于 2009-02-05T20:34:26.233 に答える
33

動的解析方法

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

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

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

動的メソッドの利点:

  • 関数ポインターと仮想 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 初期化ボイラープレートが含まれています。
  • f0、期待どおりf1f2相互に呼び出されます
  • pointed関数ポインターで呼び出したにもかかわらず、 も表示されます。コマンドライン引数を渡した場合、呼び出されなかった可能性があります。
  • not_called追加のコマンドライン引数を渡さなかったため、実行中に呼び出されなかったため、表示されていません。

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

したがって、ソース コードがなくても、実行可能ファイルだけを使用できます。

valgrind軽量の「仮想マシン」を介してコードを実行することで、なんとかそれを行うことができます。これにより、ネイティブ実行と比較して実行が非常に遅くなります。

グラフでわかるように、各関数呼び出しに関するタイミング情報も取得されます。これは、呼び出しグラフを表示するだけでなく、プログラムのプロファイリングに使用できます。これは、このセットアップの元のユース ケースである可能性があります。 Linux で実行されている C++ コード?

Ubuntu 18.04 でテスト済み。

gcc -finstrument-functions+ エトレース

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

特定のハードウェア トレースのサポート以外ではおそらく最も効率的な方法ですが、コードを再コンパイルする必要があるという欠点があります。

于 2015-07-02T16:39:39.757 に答える
18

理解は、コールグラフを作成する上で非常に優れた仕事をします。

于 2009-02-05T19:49:49.427 に答える
11

当社のDMS Software Reengineering Toolkitには、C コードの巨大なシステム (~~~2500 万行) に適用された静的制御/データフロー/points-to/call グラフ分析があり、関数ポインタを介して呼び出される関数を含むそのような呼び出しグラフを作成しました。

于 2010-12-04T20:00:51.050 に答える
6

私の bash ベースの C コール ツリー ジェネレーターは、こちらで確認できます。呼び出し元および/または呼び出し先の情報が必要な 1 つまたは複数の C 関数を指定できます。または、一連の関数を指定して、それらを接続する関数呼び出しの到達可能性グラフを決定できます...つまり、すべての方法を教えて main( )、foo()、および bar() が接続されています。グラフエンジンにはgraphviz/dotを使用しています。

于 2015-07-03T03:42:16.020 に答える
5

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

于 2009-02-17T13:32:46.740 に答える