我希望能够检测何时发生对内存地址的写入 - 例如通过设置附加到中断的回调。有谁知道怎么做?

我希望能够在运行时执行此操作(可能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

- 亚当

GDB确实具有该功能:它被称为硬件观察点,并且在Linux / x86上得到了很好的支持:

(gdb) watch *(int *)0x12345678

如果您的应用程序崩溃了GDB,请从 CVS Head 构建当前的GDB。

如果该GDB仍然失败,请提交GDB 错误

我们可以更快地修复GDB,而不是破解SIGSEGV处理程序(提供了一个很好的测试用例),并且修复GDB也可以帮助您解决未来的问题。

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附加的忙循环。从那里你可以看到谁试图写下你的记忆。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top