はじめに
Oracle VirtualBox に組み込みの debugger を,自作 OS の kernel レベル でのデバッグに使い始めました.ネットにもあまり情報が無いようなので, あれこれをまとめておきます.
Debugger の起動
GUI 環境から VirtalBox を起動した場合,debug 機能はオフになっていま すので,コマンドラインからオプションを付けて起動する必要があります. ヘルプコマンドでは3種類のオプションが表示されますが,それぞれのオプ ションで起動直後の状況が違います。
- VirtualBox --startvm <name> --dbg
- デバッグオプションが利用可能な形で VirutalBox を起動し,そのまま ターゲットも起動されます.
- VirtualBox --startvm <name> --debug
- VBoxDbg Console と情報表示用の Window を表示した状態で VirutalBox を起動しますが、ターゲットは一時停止されています.
- VirtualBox --startvm <name> --debug-comand-line
- VBoxDbg Console を表示した状態で VirutalBox を起動しますが、ター ゲットは一時停止されています.
--debug オプションや --debug-command-line オプションによって停止 している VM は,右 ctrl + P で実行に移せます.
breakpoint の設定
VirtualBox の debugger は bp や br コマンドで breakpoint を設定することが 出来ますが,この2つコマンドの違いについてあまり詳しい情報は集めら れませんでした.
やってみた結果から言うと,debugger の起動後 に stopコマンドで VM を停止させ,その後に r コマンド(レジスタの dump)や u コマンド(逆アセンブル)で表示されるアドレスを 使って breakpoint を設定するのは,どちらのコマンドでも可能でした.
VM の実行前に,仮想アドレスの番地を直接 breakpoint に設定するには br コマンドを使用する必要がありました.
symbol table の作成と読み込み
VM debugger には C 言語で作成した関数名などのシンボルと,VM マシンの アドレスを対応付けて表示してくれる機能があり,これをうまく使えるとデ バッグがかなり楽になります.
シンボルテーブルのフォーマットとしては Linux の
/proc/kallsyms で表示されるものがそのまま使
えるようです.また,このフォーマットの詳細は
16 進数の仮想アドレス番地 | t(ローカル関数)/T(グローバル関数) | シンボル名 |
このテーブルは,実行する OS の kernel image から readelf -s コマンドで読みだしたシンボルテー ブルの関数名を grep FUNC などによって抜き出 し,フォーマットを変更(python スクリプトの 例)することで作成できます.
シンボルテーブルの debugger への読み込みには loadmap コマンドを使用しますが,このコマン ドの第 3 引数(必須)は,シンボルテーブルのアドレスのオフセットを意味 するようです.kernel image の関数アドレスが絶対番地で与えられている 場合,この値は 0 にしておけば良いようです.
シンボルテーブルの読み込み後,berakpoint の設定は br _startup の用にシンボル名でできるように なりますし,uで表示される相対ジャンプなどで も,近場にあるシンボルを参照した表示行ってくれるので C 言語との関連 を付けるのが非常に楽になります.
debugger の効果
degugger (ソースコードレベルではなくバイナリレベルのもの)に慣れてい る人には余計な話でしょうが,kernel が無限ループに陥った状況で, stop で実行を中断し, u で逆アセンブルすることで,ループを脱出出 来ない理由を推定することができます.このおかげで割込 flag に使ってる 変数の volatile 宣言漏れを数カ所見つけて潰 すことができました.
メモリーアクセスも breakpoint で catch できるようなのですが,こちら はまだ成功していません.メモリー内容を破壊する bug の検出に非常に役 立ちそうなので,何とか使いたいところなのですが....