Btraxの使い方

インストール

動作環境

対応カーネル 2.6.8 - 2.6.30 (i386)
2.6.18 - 2.6.30 (x86_64)
対応プロセッサ x86, x86_64
Pentium4, PentiumM, Atom, Core, Core2, Core i series
ライブラリ binutils, elfutils, kernel-debuginfo
対応ディストリビューション Red Hat Enterprise Linux 4.0
Red Hat Enterprise Linux 4.3
Red Hat Enterprise Linux 5.0
Red Hat Enterprise Linux 5.1
Red Hat Enterprise Linux 5.4
Miracle Linux 4.0 SP1
Fedora 12

制限事項

procfs, kallsyms, apic, kprobes, relayfsがサポートされている必要がある。

OProfileなど、プロセッサの機能の一つである性能モニタリング機能(PEBS)を用いる ツールとの併用はできない。 (プロセッサの仕様により、性能モニタリング機能と分岐命令トレース機能が 同じメモリ領域で管理されるため)

ビルド, インストール

一般的なソフトウェアと同じように、tarボールを解凍し、configureスクリプトを走らせ、 make, make installすることでビルドとインストールは完了する。

$ tar xvf btrax-1.0.6.tar.gz
$ cd btrax-1.0.6
$ ./configure
$ make
$ su
# make install

Btraxの動作概要

BtraxはプロセッサにあるBTS(Branch Trace Store)と呼ばれる機能を利用している。 BTS機能はジャンプや割り込みがあったときに、ジャンプ元とジャンプ先を逐一記録する機能であり、 Btraxはこの情報を取得することでカバレッジ解析を行っている。

各コマンドの動作概要

Btraxは以下のコマンドから構成される。

コマンド名 概要
bt_collect_log BTSログ取得する。
ログ取得はプロセスの開始から終了まですべてを得る方法、 既に実行しているプロセスの任意のタイミングでログ取得する方法、 ある関数からある関数までのログ取得を行う方法、 特定のシステムコールからログ取得を開始する方法などがある。
bt_split BTSログをPIDで分離する。
bt_coverage BTSログからカバレッジを解析し、HTML形式で出力する。
解析範囲を限定することも可能である。
bt_execpath BTSログから、どのような実行パスを通ったかを表示する。
解析範囲を限定することも可能である。

各コマンドで利用可能なオプションについては リファレンスを参照のこと

アプリケーション用フック間数

アプリケーション全体のカバレージ解析ではなく、一部のみのカバレージを解析したい場合、 以下の関数を使うことで、BTSログの取得範囲を限定することができる。 これらの関数は"btrax/bt_for_ap.h"をincludeすることで利用可能となる。 なお、Btraxはデフォルトでアプリケーションの先頭からログ取得を開始してしまうため、 特定の領域のみのカバレージ解析を行いたい場合、あらかじめmain関数の頭でBTSログ取得を 停止しておく必要がある。

関数名 概要
bt_start_from_ap() この関数からBTSログの取得を開始する
bt_stop_from_ap() この関数からBTSログの取得を停止する

トレース対象とトレース手順の概要

btraxでは、トレース対象がカーネルかアプリケーションかによって、必要な手順が異なる。 以下の表にトレース対象とトレース手順の概要を示す。

# トレース対象 バイナリ再構築 トレース手順の概要
カーネル/アプリ トレース範囲
1 カーネル 任意の部分だけをトレース。例えば、ある関数だけトレース なし
  1. トレース開始/終了フック位置の確認
  2. --start,--stopの両方を指定し、スクリプト実行
2 アプリ 実行直後からの全挙動をトレース なし
  1. -c でコマンドおよびその引数を指定し、スクリプト実行
3 アプリ 任意の部分だけをトレース フック関数追加要
  1. main関数の先頭にトレース終了関数を入れる
  2. トレース開始したい部分にトレース開始関数を入れ、 トレース終了したい部分にトレース終了関数を入れる
  3. -c でコマンドおよびその引数を指定し、スクリプト実行
4 アプリ 実行中のアプリケーションをトレース なし
  1. -p で pid を指定し、スクリプト実行
5 システムコール トレース開始時に指定したアプリ(およびその子プロセス/スレッド)から 発行されるシステムコールの実行をトレース なし
  1. トレース対象システムコール間数名(sys_call_table内の間数) を確認
  2. --syscallで上記間数名を、-cコマンド(およびその引数)を指定し、スクリプト実行

カーネルの任意の部分だけをトレース

カーネルの任意の部分のカバレージ解析を行う場合、bt_collect_log--startおよび--stopオプションを追加し、 関数名で開始/終了箇所を指定する。 具体的には次のように指定する。

# bt_collect_log --start ext4_create --stop ext4_unlink -d log_dir

この例では、ext4_create関数が呼ばれたらトレースを開始し、 ext4_unlink関数が呼ばれたらトレースを終了するように指定している。 なお、-d log_dirはログを出力するディレクトリを指定している。

このコマンドは自動的に終了しないため、トレースを終了させるにははCtrl+Cを bt_collect_logに送信する必要がある。

ログ取得が完了したら、次はカバレージ解析を行う。 カバレージ解析はbt_coverageコマンドを用いる。 具体的には次のようなコマンドを発行する

# bt_coverage --ker -f cpu0,cpu1,cpu2,cpu3 -o html_dir

解析対象ログは-fオプションでログディレクトリ内のcpu0,cpu1...というファイルを渡す。 複数cpu*ファイルがある場合は、カンマ区切りで指定する。 また、今回は解析対象がカーネルであるため、カーネル空間を指定するオプション--kerを 指定する。 カバレージ解析結果の出力先は-oオプションで指定する。 bt_coverageは指定されたディレクトリを作成し、内部にHTMLファイルを書き出す。

アプリケーションの実行直後からの全挙動をトレース

アプリケーションの全挙動の解析を行う場合、 bt_collect_logでBTSログを取得する際、-cオプションで トレース対象のアプリケーションを実行するコマンドを指定する。

# bt_collect_log -d log_dir -c application_command

ログ取得が完了すると、-dオプションで指定したディレクトリが作成され、 その中にBTSログが格納される。 次にログディレクトリに入り、bt_splitコマンドでCPUごとのBTSログを PID単位に分離する。

# cd log_dir
# bt_split -d .

最後に、bt_splitコマンドによってPIDごとに分離されたログファイルを bt_coverageコマンドで解析する。 -oオプションで指定したディレクトリに カバレージ解析結果がHTMLで出力される。 また、例ではターゲットアプリケーションだけを解析するため、 ユーザ空間指定フラグである--usrオプションを渡している。 カーネル空間も合わせてカバレージ解析結果を取得する場合は、--usrのかわりに --allを使うこともできる。

# bt_coverage --usr -f PID -o html_dir
# firefox html_dir/top.html

アプリケーションの任意の部分だけをトレース

アプリケーションの任意の部分のみのカバレージ解析を行いたい場合、 アプリケーションのソースコードにトレース開始/終了用フック間数を埋め込み、 再コンパイルする必要がある。それらの関数は"btrax/bt_for_ap.h"をインクルード することで利用可能になる。

Btraxはデフォルトでアプリケーションの先頭から トレースを開始してしまうため、アプリケーションのmain関数の先頭に、 トレース終了フック間数を入れておく必要がある。 例えば、次のようにトレース開始/終了フック間数を入れる。

#include "btrax/bt_for_ap.h"

int main(int argc, char *argv[])
    bt_stop_from_ap();   /* トレース終了フック関数 */
    ...
    ...
    bt_start_from_ap();  /* トレース開始フック関数 */
    ...
    /* 解析対象コード */
    ...
    bt_stop_from_ap();   /* トレース終了 */
    ...
}

このようにトレース開始/終了フック間数を入れ、再ビルドした後は、 「アプリケーションの実行直後からの全挙動をトレース」 と同じ手順を踏むことでカバレージ解析が可能となる。

実行中のアプリケーションをトレース

既に実行されているアプリケーションのカバレージ解析を行いたい場合、 bt_collect_logでログを収集する際に-pオプションと、 解析したいアプリケーションのPIDを指定する。具体的には、以下のようなコマンドを実行する。

# bt_collect_log -p 12345 -d log_dir

-p 12345はPID=12345のアプリケーションを意味している。 ログの取得はプロセスが終了するか、bt_collect_logにCtrl+Cを送信するまで続く。

ログ取得が完了したら、カバレージ解析を行うが、この方法は 「アプリケーションの実行直後からの全挙動をトレース」と 同じである。

# cd log_dir
# bt_split -d .
# bt_coverage --usr -f PID -o html_dir
# firefox html_dir/top.html

トレース開始時に指定したアプリ(およびその子プロセス/スレッド)から 発行されるシステムコールの実行をトレース

システムコールの実行をトレースするには、bt_collect_logで ログを収集する際に--syscallオプションとカーネル内のシステムコールを処理する 関数名を渡す必要がある。 次の例では、gettimeofdayシステムコールをトレースする例を示す。

# bt_collect_log --syscall sys_gettimeofday -d log_dir -c application_command

sys_gettimeofdayはシステムコールgettimeofdayのカーネル内エントリポイントである。

次に、bt_coverageコマンドでカバレージ解析を行い、結果を出力する。 今回はシステムコール内部のカバレージ測定を行うため、カーネル空間のみを解析対象にする--ker オプションを指定し、さらに解析対象を限定する為に-Iオプションで エントリポイントsys_gettimeofdayを指定している。 また、余分な解析を行わせないため-Eオプションでschedule(), dump_stack(), printk() を省いている。

なお、今回は解析対象としてカーネルのみを指定したが、アプリケーションとカーネル、 あわせてカバレージ解析を行いたい場合は、--kerのかわりに --allを指定することもできる。

# cd log_dir
# bt_coverage --ker -I sys_gettimeofday -E schedule,dump_stack,printk -f cpu0,cpu1,cpu2,cpu3 -o html_dir
# firefox html_dir/top.html

カバレージを比較

Btraxはカバレージの比較をサポートしており、 あるアプリケーションの入力を変えるなどして、カバレージがどのように変わるかを知ることができる。 今回はlsコマンドを例にとって説明する。

まず、bt_collect_logコマンドでログを取得する。 次の例では'ls''ls -l'を実行したときのログを取得している。

# bt_collect_log -d log_dir -c ls
# bt_collect_log -d log_dir2 -c ls -l

次に、それぞれのログファイルをbt_splitコマンドによって PIDごとに分離する。

# bt_split -d log_dir
# bt_split -d log_dir2

最後に、bt_coverageコマンドでカバレージ解析を行うが、 --f2オプションで比較対象のログファイルを指定することで、 カバレージ比較結果を得ることができる。

# bt_coverage --usr -f log_dir/PID --f2 log_dir2/PID2 -o html_dir
# firefox html_dir/top.html

結果のマージ

過去に得られた複数のログファイルと、新しく実行して得られたログファイルの カバレージを比較する場合、bt_coverageコマンドに指定する -fオプションに複数のログファイルを渡すことでカバレージ比較をすることができる。

# bt_coverage --usr -f log,log2,log3,log4 --f2 new_log -o html_dir

HTMLファイルの見方

カバレージ表示

カバレージ表示

図中のOK,NT,HTはそれぞれ分岐命令の分類を表しており、OKはTaken,Untaken両方実行したことを、 NTは実行されていないことを、HTは分岐/通過の片方のみを実行したことを意味している。

カバレージ比較

カバレージ比較

実行経路を表示する

Btraxはカバレージ解析だけでなく、bt_execpathコマンドを使うことで、 実行経路を表示することもできる。 bt_execpathコマンドで指定できるオプションは リファレンス#bt_execpathを参照。

使用例

bt_execpathの使用例を示す。

# bt_execpath --usr -s -f log_dir/PID

例では、プロセスごとに分割されたログファイルを読み、 ユーザ空間だけを解析対象にし、サマリ表示を行うように指定している。

出力形式

bt_execpathサマリ表示

リファレンス

bt_collect_logで利用可能なオプション

オプション 意味
-d DIR_NAME ログ出力先ディレクトリを指定する
--start SYMBOL
--stop SYMBOL
トレース開始/終了する関数名を指定する
-p PID 指定したPIDのアプリケーションをトレースする
-c COMMAND COMMANDによって実行されるアプリケーションをトレースする
--syscall FUNC_NAME,FUNCNAME2,... システムコールのトレースを行う。 FUNC_NAMEにはカーネル内のシステムコールエントリポイントを指定する。
例: sys_open

bt_splitで利用可能なオプション

オプション 意味
-d DIR_NAME ログディレクトリを指定する

bt_coverageで利用可能なオプション

オプション 意味
-f LOG_FILE,LOG_FILE2,... 解析対象ログファイルを指定する
-o DIR_NAME カバレージ解析結果HTMLの出力先ディレクトリを指定する
--usr
--ker
--all
-a ADDR:ADDR
解析対象アドレス範囲を指定する。
--usrはユーザ空間のみ
--kerはカーネル空間のみ
--allは全空間
-a ADDR:ADDRではユーザがアドレス範囲を直接指定することができる
例えば、-a 0xffffffff80000000:0xffffffffffffffffのように指定可能である。
-I FUNC_NAME,FUNC_NAME2,... 解析対象の関数を指定する
-E FUNC_NAME,FUNC_NAME2,... 解析対象から除外する関数を指定する
--f2 LOG_FILE,LOG_FILE2,... -fで指定したログファイルとの比較用ログファイルを指定する
-S SOURCE_DIR
--S2 SOURCE_DIR
Btraxが自動的にソースコードの情報を得ることができなかった場合、 このオプションを使い、ソースコードのディレクトリを指定することができる。

bt_execpathで利用可能なオプション

オプション 意味
-s サマリ表示をする
--usr
--ker
--all
-a ADDR:ADDR
解析対象アドレス範囲を指定する。
--usrはユーザ空間のみ
--kerはカーネル空間のみ
--allは全空間
-a ADDR:ADDRではユーザがアドレス範囲を直接指定することができる
例えば、-a 0xffffffff80000000:0xffffffffffffffffのように指定可能である。
-f FILENAME ログファイルを指定する