simotin13's message

simotin13といいます。記事の内容でご質問やご意見がありましたらお気軽にコメントしてください\^o^/

Intel Pin を使ってコードカバレッジツールを作ってみた

一年ほど前にGDBを使ったコードカバレッジツールを作っていましたが、
mcommit.hatenadiary.com
最近少し時間ができたのでIntelPinという動的バイナリ計装エンジン(Dynamic Binary Instrumentation Engine)を使う形で改めて作ってみました。
IntelのPinプラグインを書くのは初めてだったので使い方やバイナリ計装について調べたので諸々を記事に書いておきたいと思います。

Intel Pin とは何か?

Intel Pin は文字通りIntelが公開している動的バイナリ計装エンジンです。ユーザアプリケーションを実行時に計装くれて、実行した命令やメモリアクセス、関数呼び出し時のレジスタの値など、様々な情報を収集することができます。プラットフォームはLinuxWindowsに対応しているようです。
正式名称は Pin のようなので以降はPinで統一して記載します。

Pin本体はDBI(Dynamic Binary Instrumentation)のエンジンであり、Pinの利用者はPinが提供するAPI(C++)を使って実行時の情報を取得するコードを実装することができます。Pinの様々な機能(API)を利用したツールやサンプルのソースコードは公開されていますが、Pinの本体のソースコードは公開されておらず実行モジュールとして提供されています。

DBI は何をしているのか?

DBIの利用者は実行中のプログラムから様々な情報を取得するコードを実装することになります。
DBIエンジンはターゲットプログラムの関数を解析し、DBIのユーザが実装したコードを埋め込んだ関数を生成します。これは計装・パッチングと呼ばれます。
そして、ターゲットとなるプログラムの初回の関数呼び出しをフックし、JITコンパイルにより、計装された関数を呼び出すような変更が行われます。
ちなみに、実行時ではなく静的にバイナリ計装する研究もあるそうですが、静的なバイナリ計装だと得られる情報が少ないため適切な計装ができないため、動的バイナリ計装の方がよく使われているそうです。

Pinの使い方

Pinの使い方はそこまで難しくありません。PinはPin kitと呼ばれる実行モジュールとツール等を含んだ形で配布されています。
まずはPinのサイトからPin kitをダウンロードします。

www.intel.com

tar.gzで圧縮されているので解凍します。

# 解凍例
$tar xf pin-3.27-98718-gbeaa5d51e-gcc-linux.tar.gz

APIの利用例やツール類は sources/tools以下にソースコードがあります。
ツール一式もここにあるので make を実行すればビルドされます。

$ cd sources/tools
$ make

Pinの実行方法

pinコマンドはDBIエンジン本体になります。利用者は共有ライブラリとして実装したツールを読み込んで実行します。
実行する際は以下のような形でコマンドを実行することになります。

cd <pin_kit_path>
./pin -t ./<tool_module>.so -- <target_module_path> <target_args...>

は解凍したPin kitのパスです。
ここでの.soは実装したツール(共有ライブラリ)です。
は計装したいターゲットモジュールです。はターゲットモジュールに渡す起動引数になります。

Pin のAPIの利用法

PinのAPIは Pin kit に含まれるpin.Hをインクルードすることで利用できます。
詳細はユーザガイドやAPIのリファレンス、sources/tools以下の実装例を参考にして頂ければと思います。

software.intel.com


PinのAPIを利用する実装の大まかな流れは、

  1. PIN_Initにより初期化を行う
  2. IMG_AddInstrumentFunction,INS_AddInstrumentFunctionで必要に応じた計装処理を登録する
  3. PIN_AddFiniFunctionで実行終了時の処理(解析結果の出力やリソースの開放など)を登録する
  4. PIN_StartProgramでPinの実行を開始する

といった流れになります。

Makefileについて

Pinのツールを自作する場合、sources/tools/MyPinTool をひな型として利用するようです。
MyPinToolをコピーして、フォルダ名やファイル名を適切に変更していくことで自作のツールが実装できます。

ツールのフォルダをPin kitの外に配置する場合、

make PIN_ROOT=../pin-3.27-98718-gbeaa5d51e-gcc-linux

のようにPin kitのフォルダパスを指定してmakeコマンドを実行する必要があります。

Pinを使ってみたきっかけ

Pin 以外のDBIエンジンとしては、

といった実装があるそうです。

QDBIについてはこちらのYouTubeの動画で詳細が説明されています。
計装の仕組みとして、LLVM IRを利用することで計装を実現しているそうです。
www.youtube.com

私がPinを使ったコードカバレッジツールを書いてみたのは偶然こちらの動画を見たことがきっかけでした。

上記の動画中で、

プログラムの動的解析には

  • デバッガを使う
  • 動的バイナリ計装を使う

方法があるがデバッガを使う方法はめっちゃ遅い

ということが解説されています。
実際、私が以前作ったデバッガ(GDB)を使うカバレッジツールは規模の大きなプログラムのカバレッジを取るのにはかなり時間がかかっています。マイコンを使うような組み込み開発でカバレッジを取りたくて作ったものなのでx64のアプリケーションのトレースに時間がかかることはそこまで気にしていませんでしたが、もっとパフォーマンスのよいものが作れるならつくってみたいなぁと何となく思っていたところこのDBIのことを知り、Pinを使えばできそうということで作ってみたというところです。

作ってみたカバレッジツールについて

以下のレポジトリで公開しています。
github.com

具体的な使い方についてはREADMEの方に書いておりますのでこちらでは詳しくは触れませんが、
00_setup.sh, 01_run_example.sh の簡単な動作確認用のスクリプトを実行して頂ければ雰囲気や使い方を理解して頂けるかと思います。

00_setup.sh

でpinのダウンロードとカバレッジツールのビルドを行います。

01_run_example.sh

で同梱している簡単なCのプログラムのカバレッジを取ります。

機能も増やそうと思ってコードを触っている途中ですが、Pinツールを自作する際の参考になればと思います。

参考書籍・参考サイト

Pin を使ってみるにあたって、実践バイナリ解析という本を参考にさせて頂きました。動的バイナリ計装の仕組みの解説されいておすすめです。
Pin の利用例としてプロファイリングツールの実装例が取り上げられています。


pinの使い方については以下のサイトを参考にさせて頂きました。
inaz2.hatenablog.com

感想

PinにはいろんなAPIが提供されていて、DWARFの行番号情報もAPIを使って取得することができました。*1
提供されているAPIをうまく使うと面白いことができそうです。もう少し調べてコードカバレッジツールに便利な機能を増やしていきたいと思います。

*1:ただしDWARF4