2007-09-27 BGM: 夜の矢上を往く [長年日記]
λ. 第 336 回 PTT 「仮想マシンを利用したプログラムの実行の監視とそのデバッガへの応用」
久しぶりにPTTに参加。 そして、初めて矢上に来た(慶應に6年もいて矢上に来るのが初めてというのもどうかと思うが)。
以下、簡単なメモ。
背景
伝統的なデバッガが共通して持つ機能は、ブレークポイント、ステップ実行、変数の値の調査等だが、これだけでは大規模で複雑なプログラムのデバッグには不十分。逆実行や、不具合に関係のある部分を抽出するスライシングの機能が必要。
仮想マシンの概観
- コード変換エンジン
- 動的な instrumentation を用いながら個々のスレッドを実行する
- スレッドシステム
- スレッドスケジューリングや Pthread API のエミュレートを行う
- 実装は GNU Pth を基にした
- GNU Pth はプリエンプションには対応していないが、 コード切り替えを起こすようなコードを dynamic instrumentation で埋め込むことで対応
コード変換
- 監視コードの挿入
- デバッガ側の要求に従い、イベントに対応するハンドラを呼ぶ
- イベント : デバッガの監視する挙動 (e.g. メモリの読み書き)
- ハンドラ : C言語で記述された関数
- デバッガ側の要求に従い、イベントに対応するハンドラを呼ぶ
- 分岐先の変更
- 本来の分岐先に分岐せず、仮想マシンに制御を戻す
主な監視対象
- 基本的なもの
- メモリの読み書き、レジスタの読み書き、分岐、関数の呼び出し、復帰、システムコール
- マルチスレッドに関連したもの
- スレッドの作成・終了・コンテキストスイッチ・排他制御
実行の記録・再生
- 全く同じプログラムでも、実行するたびに結果が変わってしまうことがある(プログラムの実行の非決定性)
- デバッグを行う際に大きな問題となる
- ⇒ 仮想マシンに実行を記録・再生する機能を導入
- 非決定性の要因となる振る舞いを記録・再生する (e.g. システムコール、シグナル、コンテキストスイッチ)
スライシング
- Dynamic Data Slicing
- Forward Computation という手法を用いる
- Dynamic Data Slicing
- 動的な依存関係を分析 (def-use chain)
- Forward Computatin
- プログラムの実行と同時に、並行してスライスを計算する
- backward computation に比較して消費するメモリ量が少ない
可逆実行
- ロギング方式[Chen01]と再実行方式[Boothe00]がある。
- ロギング方式 実行時に状態履歴を保存し、後に復元
- e.g. メモリ変更時に、変更前の内容を保存しておく
- 再実行方式 : プログラムを先頭から再実行する
- 適切な時点で停止させることにより、擬似的な逆実行を実現
- ロギング方式 実行時に状態履歴を保存し、後に復元
- ロギング方式の特徴
- 利点: 単距離の逆実行は比較的高速
- 欠点: ログ取得のコストが大きい。マルチスレッドには対応しづらい (終了したスレッドを復元したりする必要)
- 再実行方式の特徴
- 利点: 実装が比較的容易、ログ取得のコストもない
- 欠点: 逆実行に時間がかかる場合がある
- 両方実装したが、スレッドを使う場合には再実行方式のみ。
追記
丁度、先日 Google Japan Blog: Debugging Backwards in Time - Google Tech Talk 紹介シリーズ ( 2 ) に逆実行出来るJavaデバッガの話が出ていた。