【发布时间】:2009-03-03 22:54:12
【问题描述】:
我希望能够检测写入内存地址的时间——例如通过设置附加到中断的回调。有人知道怎么做吗?
我希望能够在运行时执行此操作(可能 gdb 具有此功能,但我的特殊 应用程序导致 gdb 崩溃)。
【问题讨论】:
我希望能够检测写入内存地址的时间——例如通过设置附加到中断的回调。有人知道怎么做吗?
我希望能够在运行时执行此操作(可能 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 有 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 方法由一些充当“调试器”的“外部进程”工作,附加到您的程序,为调试寄存器注入新值,并终止您的程序继续设置新的硬件断点。问题是,您可以使用 fork() 自己创建这个“外部进程”(我没有成功使用 pthread),并在代码中内联执行这些简单的步骤。
addwatchpoint 代码必须适应 64 位 linux,但这只是将 USER_DR7 等更改为 offsetof(struct user, u_debugreg[7])。另一件事是,在 PTRACE_ATTACH 之后,您必须等待被调试者真正停止。但是,与其在繁忙的循环中重试 POKEUSER,不如在您的 pid 上使用 waitpid()。
使用 ptrace 方法的唯一问题是您的程序一次只能连接一个“调试器”。因此,如果您的程序已经在 gdb 控制下运行,则 ptrace 附加将失败。但就像示例代码一样,您可以为 SIGTRAP 注册一个信号处理程序,在没有 gdb 的情况下运行,当您捕获到信号时,进入一个忙循环等待 gdb 附加。从那里你可以看到谁试图写下你的记忆。
【讨论】: