デバッガの実装(C/C++編)
デバッガの実装について興味があるので調べてみました。
まずは、基本であるC/C++(さらには、アセンブラ)のデバッガについて。
解説
一般的なOS(Unix, Windows等)では、セキュリティを守るためなどの目的で、OS上で動作しているアプリケーションのデータをプロセスごとに独立した仮想アドレス上に配置し、
CPUのレジスタも個々のプロセス*1ごとに管理します。
このため、debuggerがdebuggeeのレジスタ、メモリの値を読んだり、書き変えたりするには、
OSの力を借りる必要があります。
また、debugeeの実行中に発生するハードウェア、ソフトウェア割り込みを元にOSが生成する非同期イベント
(Unix/Linux系ではシグナル、Windowsでは構造化例外と呼ぶ。以下シグナル)の中には、
debuggeeが受け取る前に、debuggerが先に受け取って処理を行いたいシグナルが存在する*2ので、
debuggerはdebuggeeのシグナルをフックさせてくれとOSにお願いしなければいけません。
それ以外に、debuggeeの実行、終了、新規スレッドの追加、動的ライブラリのload, unloadなどのイベントも知りたいので、
これらのイベントもdebuggerに通知するようにOSにお願いする必要があります。
デバッグAPIの例
- Linux
- Windows
- CreateProcess関数(の引数で渡す、DEBUG_PROCESSやDEBUG_ONLY_THIS_PROCESSフラグ)
- DebugActiveProcess関数
- Set(Get)ThreadContext関数(レジスタの値の読み書き)
- Read(Write)ProcessMemory関数
たいていのOSのAPIは、
- debuggerがdebugeeプロセスを監視する権利を獲得し、debuggeeのシグナルやイベントの通知をOSから渡してもらえるようにする*4( PTRACE_ME, PTRACE_ATTACH, CreateProcess関数、DebugActiveProcess関数)
- レジスタやメモリの読み書きを行う
という手順で使われるようです。
ちなみに、各debuggeeの監視が行えるプロセスは1つしか許されないようで、
このことを利用したアンチデバッギング(プログラムの解析やチート行為などを回避するためにデバッグを防止すること)の手法がWizard Bible vol.32に書いてありました。
http://wizardbible.org/32/32.txt
breakpoint
breakpointには、主に2種類あります。
- software breakpoint
debuggeeの中のbreakpointを仕掛けたい命令を、主にデバッグのために利用するCPUのソフトウェア割り込み命令(x86系CPUだとint 3命令)に書き換える。書き換えた割り込み命令が実行されたら、そのシグナルをdebuggerがキャッチして、仕掛けた割り込み命令を元の命令に書き換えてdebuggerのユーザの入力待ちに移行します
- hardware breakpoint
CPUによっては、メモリのアドレスを格納し、このアドレスの命令やデータにアクセスする際に割り込みを発生させるCPUレジスタが存在する場合があります。これを使って割り込みを発生させ、その割り込みに対応するシグナルをdebuggerがキャッチして、debuggerのユーザの入力待ちに移行します
software breakpointの場合、debuggeeのメモリを書き換える必要があるのに対して、
hardware breakpointの場合、書き換える必要がないのがポイントです。
その他の機能
スタックトレースやステップ実行、ウォッチポイント等の機能は、レジスタやメモリの読み書きとbreakpointを応用することで実現できます。
C/C++のソースコードレベルでbreakpointを仕掛けたり、変数の値を見るためには、シンボルテーブル*5などを持つデバッグ情報(dwarf, stabs, coff等、複数の形式がある)が必要になります。
このあたりの話も書くと長くなるし、調べ切れてないので、いつか機会があったら書くことにします。
デバッガに関する話は、以下の本にかなり詳細に書かれてるので、興味を持った方は読んでみてください。
デバッガの理論と実装 (ASCII SOFTWARE SCIENCE Language)
- 作者: ジョナサン・B.ローゼンバーグ,Jonathan B. Rosenberg,吉川邦夫
- 出版社/メーカー: アスキー
- 発売日: 1998/02
- メディア: 単行本
- 購入: 8人 クリック: 108回
- この商品を含むブログ (31件) を見る