题
我希望能够检测何时发生对内存地址的写入 - 例如通过设置附加到中断的回调。有谁知道怎么做?
我希望能够在运行时执行此操作(可能gdb具有此功能,但我的特殊功能 应用程序导致gdb崩溃。)
解决方案
如果要拦截对一系列地址的写入,可以使用 mprotect( )
将有问题的内存标记为不可写,并使用 sigaction()
捕获生成的SIGSEGV,执行日志记录或其他任何操作,并将页面标记为可写入。
其他提示
您需要访问X86调试寄存器: http://en.wikipedia.org/wiki / Debug_register
您需要在DR0到DR3之一中设置断点地址,然后在DR7中设置条件(数据写入)。将发生中断,您可以运行调试代码来读取DR6并找到导致断点的原因。
如果GDB不起作用,您可以尝试使用更简单/更小的调试器,例如 http:// sourceforge。 net / projects / minibug / - 如果不起作用,你至少可以通过代码了解如何自己在处理器上使用调试硬件。
此外,还有一个很好的IBM开发人员资源来掌握Linux调试技术,它应该提供一些额外的选项:
http://www.ibm.com/developerworks/linux/library / 1-调试/
关于这样做的一篇相当不错的文章就是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有thread_set_state(),它相当于SetThreadContext()。
linux的问题在于它没有这样的等价物。我找到了ptrace,但我想,这不可能,必须有更简单的东西。但事实并非如此。然而。我认为他们正在为内核和用户空间开发hw_breakpoint API。 (参见 http://lwn.net/Articles/317153/ )
但是当我发现这一点时: http://blogs.oracle.com/nike/entry / memory_debugger_for_linux 我试了一下它并没有那么糟糕。 ptrace方法通过一些“外部过程”来工作。充当“调试器”,附加到程序,为调试寄存器注入新值,并终止程序继续使用新的hw断点集。问题是,你可以创建这个“外部流程”。你自己使用fork(),(我没有使用pthread成功),并在你的代码中内联这些简单的步骤。
addwatchpoint代码必须适用于64位linux,但这只是将USER_DR7等更改为offsetof(struct user,u_debugreg [7])。另一件事是在PTRACE_ATTACH之后,你必须等待调试对象实际停止。但是,不要在繁忙的循环中重试POKEUSER,正确的做法是在你的pid上使用waitpid()。
ptrace方法的唯一问题是你的程序只能有一个“调试器”。一次附上。因此,如果您的程序已在gdb控件下运行,则ptrace attach将失败。但就像示例代码一样,您可以为SIGTRAP注册一个信号处理程序,在没有gdb的情况下运行,当您捕获信号时,输入一个等待gdb附加的忙循环。从那里你可以看到谁试图写下你的记忆。