2007年06月13日
オープンソースを楽しむエンジニア達のこだわり 〜 ftrace で引数を表示する
先日、
プログラムの動作をトレースするツールとして ftrace を公開しました。
その後 KLab では引き続き機能拡張を行っており、関数に渡された引数を表示
するような改良を行いました。引数が解ると自作した関数の意図しない動作を
追うときにとても便利そうです。
以下からダウンロードしておためしください
注意点
- x86(32bit) な環境でしか動作しません
- デバッグ対象のプログラムは -g と -finstrument-functions フラグを付けてコンパイルされている必要があります。
- 依存するライブラリは glib1.2, libelf, libdwarf です debian sarge の方は
$ apt-get install libglib1.2-dev libelfg0-dev libdwarf-devを実行すると ./configure が通るようになります。sarge で無い方は libdwarf-dev パッケージがありませんので以下の場所から libdwarf をダウ ンロードしてインストールしてください
主な実装方針は、
- 1) 実行バイナリから引数の型情報を得る
- 2) スタックフレームから引数情報を得て表示する
(1)にある引数の型情報を得る方法の前に、まずは(2)のスタックフレームから 引数情報を得る方法について紹介したいと思います。
まず、以下のように引数を2つ受け取る関数 func() が定義されているとします
void func(int a, int b) { } int main(int argc, char *argv[]) { func(1, 2); }
この関数 func() を前回紹介した __cyg_profile_func_enter() 関数で hook した際に関数 func() の引数を得るにはどうしたらよいかを考えてみたところ gcc に は __builtin_frame_address() というスタックフレームアドレスを得るビル トイン関数が用意されていることが判ったのでこれを使ってみることにしまし た。
__cyg_profile_func_enter() を以下のように定義すると
void __cyg_profile_func_enter( void *this, void *callsite ) { if(this == func){ void *frame = __builtin_frame_address(1) + 8; printf("a=%d\n", *(int*)frame); frame += 4; // 変数 a は int なので 4byte 次へ printf("b=%d\n", *(int*)frame); } }実行結果
a=1 b=2
というように __cyg_profile_func_enter() の中から関数 func の引数を得る ことが出来ました。 この様に関数の引数が int 型であることと引数の数が判っているば正しく表 示することは出来ましたが、引数の数や型が判らないとスタックフレームの中 から正しく引数情報を得ることは出来ません。
そこで(1)に書いたように、実行バイナリから引数の数や型情報を含めた関数 のプロトタイプ情報が必要になるのですが、この方法については次回紹介させ て頂きたいと思います。klab_gijutsu2 at 15:24│Comments(0)│TrackBack(0)