たとえば、割り込みにアタッチされたコールバックを設定することにより、メモリアドレスへの書き込みがいつ発生したかを検出できるようにしたい。誰かが方法を知っていますか?
実行時にこれを実行できるようにしたいと思います(おそらく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() を使用できませんでした。
Adam が言ったように、必要なのはデバッグ レジスタを操作することです。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 がアタッチされるのを待つビジー ループに入ることができます。そこから、誰があなたの記憶を書き込もうとしたかがわかります。
GDB にはその機能があります。これはハードウェア ウォッチポイントと呼ばれ、Linux/x86 で非常によくサポートされています。
(gdb) watch *(int *)0x12345678
アプリケーションが GDB をクラッシュさせる場合は、 CVS Headから現在の GDB を構築してください。
それでも GDB が失敗する場合は、GDBバグを報告してください。
SIGSEGV ハンドラーをハックするよりも早く GDB を修正できる可能性があります (適切なテスト ケースが提供されている場合)。GDB の修正は、将来の問題にも役立ちます。