アドレスへの書き込みをトラップすることが可能(x86-Linux)
質問
たとえば、割り込みに接続されたコールバックを設定することにより、メモリアドレスへの書き込みが発生したことを検出できるようにしたい。誰もが知っていますか?
実行時にこれを実行できるようにしたい(おそらくgdbにはこの機能がありますが、 アプリケーションによりgdbがクラッシュします)。
解決
アドレス範囲への書き込みをインターセプトする場合は、 mprotect( )
で問題のメモリを書き込み不可としてマークし、 sigaction()
を使用して、結果のSIGSEGVをキャッチし、ロギングなどを行って、ページを再び書き込み可能としてマークします。
他のヒント
必要なのは、X86デバッグレジスタへのアクセスです。 http://en.wikipedia.org/wiki / Debug_register
DR0からDR3のいずれかでブレークポイントアドレスを設定し、DR7で条件(データ書き込み)を設定する必要があります。割り込みが発生し、デバッグコードを実行してDR6を読み取り、ブレークポイントの原因を見つけることができます。
GDBが機能しない場合は、 http:// sourceforgeのような単純なデバッガーを試してください。 net / projects / minibug / -それが機能しない場合は、少なくともコードを調べて、プロセッサでデバッグハードウェアを使用する方法を自分で理解できます。
また、いくつかの追加オプションを提供するLinuxデバッグテクニックの習得に関する優れたIBM開発者リソースがあります。
http://www.ibm.com/developerworks/linux/library / l-debug /
これを行うためのかなり良い記事はwindowsです(Linuxで実行していることは知っていますが、Windowsでそれをしたいという質問に他の人が出くわすかもしれません):
http://www.codeproject.com/KB/debug/hardwarebreakpoint.aspx
-アダム
mprotectには欠点があります。メモリはページ境界に揃える必要があります。スタックに問題のあるメモリがあり、mprotect()を使用できませんでした。
アダムが言ったように、あなたが望むのはデバッグレジスタを操作することです。 Windowsでは、これを使用しました。 http://www.morearty.com/code/breakpoint/それは素晴らしく機能しました。また、Mach-O(Mac OS X)に移植しましたが、うまく機能しました。 Mach-OにはSetThreadContext()と同等のthread_set_state()があるため、これも簡単でした。
Linuxの問題は、そのような同等物がないことです。私はptraceを見つけましたが、これは不可能だと思ったのです。もっと簡単なものがあるはずです。しかし、ありません。まだ。彼らは、カーネルとユーザー空間の両方でhw_breakpoint APIに取り組んでいると思います。 ( http://lwn.net/Articles/317153/ を参照)
しかし、私がこれを見つけたとき: http://blogs.oracle.com/nike/entry / memory_debugger_for_linux 試してみましたが、それほど悪くはありませんでした。 ptraceメソッドは、「外部プロセス」によって機能します。 「デバッガ」として機能し、プログラムにアタッチし、デバッグレジスタに新しい値を挿入し、新しいハードウェアブレークポイントセットでプログラムを終了します。問題は、この「外部プロセス」を作成できることです。 fork()を使用して(pthreadで成功しませんでした)、コード内でこれらの簡単なステップをインラインで実行します。
addwatchpointコードは、64ビットLinuxで動作するように適合させる必要がありますが、USER_DR7などをoffsetof(struct user、u_debugreg [7])に変更するだけです。もう1つは、PTRACE_ATTACHの後、デバッグ対象が実際に停止するのを待つ必要があるということです。ただし、ビジーループでPOKEUSERを再試行する代わりに、pidでwaitpid()を実行するのが適切です。
ptraceメソッドの唯一の問題は、プログラムに「デバッガ」を1つだけ含めることができることです。一度に添付。そのため、プログラムがすでにgdbの制御下で実行されている場合、ptrace接続は失敗します。ただし、サンプルコードと同様に、SIGTRAPのシグナルハンドラーを登録し、gdbなしで実行し、シグナルをキャッチすると、gdbの接続を待機するビジーループに入ります。そこから、誰があなたの記憶を書き込もうとしたかを見ることができます。