2006年1月23日

Jockey で Linux のプログラムの実行を記録・再生する

Jockey は Linux のプログラムの実行を記録・再生するツールです。システムコールと一部の CPU命令をフックして実行時の入出力をログに記録することによってプログラムの再生を実現しています。主にデバッグ用途に使います。

 

インストール

Jockey は Debian パッケージになっていないため、ソースコードからビルド・インストールしました。事前に ruby, boost, zlib などをインストールしておく必要があります。

本記事を執筆している時点で Jockey の最新版は 0.8.1 です。手元の Debian GNU/Linux の環境ではこのようなパッチを当てる必要がありました。ビルド・インストールは普通に ./configure && make && sudo make install を実行すれば OK です。

使い方

Jockey を使ってプログラムの実行を記録・再生する方法にはいくつかありますが、もっとも簡単なのは jockey コマンドを使う方法です。たとえば /bin/date の実行を記録するには次のように実行します。

% jockey /bin/date
Warning: /bin/date is, by default, excluded from tracing.
Warning: I'm adding 'excludedprogram=-' option as a courtesy.
2006年  1月 23日 月曜日 01:23:39 JST

警告が気になる場合は --excludedprogram=- を jockey の引数に渡せば消えます。上で記録した /bin/date の実行を再生するには次のように実行します。

% jockey --replay=1 /bin/date
2006年  1月 23日 月曜日 01:23:39 JST

何度再生を行っても、さきほどとまったく同じ時刻が表示されるところがポイントです。これは /bin/date 実行を記録する際にシステムコール gettimeofday(2) の値がログに書き出され、再生時にはログに記録された値が用いられるためです。 ログには他にもたくさんの情報が記録されています。

Jockey はソケットを使ったプログラムの記録・再生もできます。

% jockey  wget -qO- 'http://www.random.org/cgi-bin/randnum?num=5'
17      81      81      38      18
% jockey --replay=1 wget -qO- 'http://www.random.org/cgi-bin/randnum?num=5'
17      81      81      38      18

この例では random.org のrandom.org のサービスを使ってランダムな整数を5つ取得しています。再生時には記録時とまったく同じ結果が得られています。再生時には実際のネットワークアクセスを行わず、ログを元にデータの入力を再現しています。ネットワークアクセスが起きないため、再生は高速です。

仕組み

Jockey の本体は libjockey.so という共有ライブラリです。libjockey.so を LD_PRELOAD に指定するだけで任意のプログラムを再生・記録できるため、ソースコードの編集や再リンクなどは不要です。上の実験で用いた jockey コマンドは環境変数 LD_PRELAOD と JOCKEYRC を適切に設定するだけのラッパーです。

Jockey はシステムコールと、非決定的な動きをする一部の CPU 命令 (現在は rdtsc のみ) の呼び出す部分のコードを実行時に書き換えて (パッチを当てて)、元のシステムコール・CPU命令ではなく、ログの再生・記録が可能な Jockey が用意したコードを呼ぶようにします。これを実現するために x86 命令のテーブルベースのパーザと libdisasmというディスアセンブラ・ライブラリを用いています。パッチを当てない部分は元のコードがそのまま走ります。

詳しい仕組みは Jockey の論文 で解説されています。mmap(2) やシグナルを処理する手法など、非常に興味深い内容です。

まとめ

Jockey を使うと任意の Linux のプログラムの実行を記録・再生できます。 Jockey はたとえば再現性の低いバグをデバッグするときに使えます。10回に1回しか再現しないようなバグでも、Jockey を用いて問題が再現するまで記録すれば、問題が起きたときのログを用いて何度でも再現できるようになります。再生は GDB 上で行うこともできます。

このようなデバッグを行う場面はそれほど多くはないかもしれませんが、覚えておくといざというときに役立つかもしれません。役に立たないとしても技術的におもしろいので、覚えておいて損はなさそうです。