UNIXプログラミング

【C言語】プログラムを動的トレース解析するツールと動的コールグラフを実装しよう!

今回は、instrument-functions GNU拡張を使って、

プログラムを動的にトレース解析してくれるデバッガを実装していきます。

関数をトレースするツールのプログラム

まずはどのタイミングで、どの関数を呼び出されて、終了したかを追跡してくれるプログラムを作ってみましょう。

まずはプログラムのソースコードをみてください。

このプログラムでは、普段使わないような見慣れない関数が記述されていると思うのですが、

__cyg_profile_func_enter()__cyg_profile_func_exit()は、関数が呼び出されたとき、関数が終了したときに実行される関数です。

それぞれの関数の第一引数(addr)には呼び出された関数の情報が、第二引数(site_call)には呼び出した関数の情報が入っています。

また、addr2name()は関数名を返す関数です。

これらを使って関数をトレースしていくわけですが、

無限ループを防ぐために、__cyg_profile_func_enter()__cyg_profile_func_exit()などには、

__attribute__((no_instrument_function))という記述を付け足します。

この記述が付け足された関数は、

『呼び出しと終了の際に__cyg_profile_func_enter()と__cyg_profile_func_exit()が呼び出され無くなる』

ということを意味します。

このプログラムを実行すると、

しっかりとトレースができていることが分かります。

>>>は関数の開始を、<<<は終了を表しています。

また一番右の()の中は関数アドレスを表します。

動的コールグラフを生成するプログラム

関数をトレースするプログラムを生成したので、

次は関数の主従関係を表す動的コールグラフを生成してみましょう。

まずはソースコードから。

このプログラムでは関数が呼ばれたときに、

__cyg_profile_func_enter()で呼ばれた関数名を登録するようにしています。

その際にmain関数が呼び出された場合(プログラムの開始時)に限って

cg.dotファイルに有効グラフを記述するprogram_exit()をatexit()を使ってプログラム終了時に呼び出すように設定しています。

このプログラムを実行すると、以下のような内容のcg.dotというファイルが生成されます。

これはGraphViz形式で表された動的コールグラフで、dot命令でPNGやSVGに変換することができます

これを、

で実行すると、以下のPNG画像が表示されます。

(もしGraphVizをインストールしていない人は、先にインストールを済ませておいてください。)

生成される画像は呼び出した関数から呼び出された関数への有向グラフになっています。

また、ラベルの数字は、呼び出し元が何回だけその関数を呼び出したかを表しています。

このプログラムを使うと、関数の主従関係が視覚的に分かるようになります。