memologuememologue読者になるmemologueこの広告は、90日以上更新していないブログに表示しています。関数コールトレーサbinaryでかいソフトウェアの、大量のソースコードを短時間で読む必要が生じたので、その補助ツールとしてptrace(2)ベースのLinux用関数トレーサを自作しました。いうツール上でまずソフトウェアを実行してみて、どのファイルのどの関数がどういう順で呼ばれるか把握おけば、いきなりソースコードの山と格闘を始めるより楽かなーと思いまして。作ったので公開します。http://binary.nahi.to/hogetrace/straceはシステムコールだけ、ltraceは共有ライブラリ(DSO)の関数呼び出しだけ*1をトレースしますが、このツールは、実行バイナリ中の自作関数の呼び出しもトレースします。s;}最適化なしで普通にコンパイルしてトレーサにかけてみるとこんな感じの出力になります。つけると、ファイル名/行番号を出せるので、そうしてあります。done結果の55が計算され、表示されるまでの関数の呼び出し状況がわかると思います。-finstrument-functions系のトレーサを使わせてもらおうと思っていたのですが、(私の解析したいソフトウェアの場合)ソフトウェアの再コンパイルやMakefileの書き換えに大変手間がかかることがわかったので、「stripされていなければ再コンパイル不要」なツールを自作してみたという感じです*2。連休もあることだし、勉強がてら。ptrace(2)ベースで、fork/exec/clone対応、DSOの関数呼び出しのトレースも対応、です。関数の引数表示のところは、ftraceのソースコードをそのまま流用させていただきました。ありがとうございます。(あとでちゃんと書く):libbfdを使って解析対象のプログラムの.symtabを読んで、全関数の先頭アドレスを得ている。スタック見て動的にやる方法もありますが、今回は静的にやった。ltraceとは違う方法にしてみたかったというのもあるし、マルチスレッド環境で動的にセットしたBPを別スレッドが踏むとめんどくさいというのもあったり。callではなくjmpにしちゃうとか、探すときに細かい注意点がある。ひとつの関数内に複数のretが存在することが(もちろん?)ある。switch-case使ったときとか。見て、関数の定義されているファイル名、行番号の情報を取得している。見て、関数の引数の情報を取得している。解析対象をforkしてptrace(TRACEME);してsetenv(LD_BIND_NOW=1);してexec。PLT経由の関数呼びの初回(_dl_runtime_resolve時)がすぐにreturnするように表示されてしまう。子プロセスの起動時間を延ばしてしまう悪いhackかも。解析対象がメモリにロードされたら、関数の先頭アドレス、RET命令アドレスにブレークポイント設定。ptrace(POKE)でそのアドレスに0xCCを書くだけ解析対象が0xCCを踏むと、tracefにシグナルで通知がくる。0xCCで止まった解析対象の再開方法は、gdbとかと同じ(説明になっていない)。EIPを戻して元の命令書き戻してシングルステップして云々。Language)」あたりを。0xCCを仕掛けておく。jmp*を踏んで解析対象が止まったら、解析対象のスタック上のリターンアドレスをPEEKして、tracef側に記憶する。0x..のアドレスにすりかえる(POKE)。