4

以前有时在带有简单 MMU 的嵌入式系统上工作时,我曾经动态地对该 MMU 进行编程以检测内存损坏。

例如,在运行时的某个时刻, foo 变量被一些意外数据覆盖(可能被悬空指针或其他)覆盖。所以我添加了额外的调试代码:

  • 在初始化时,foo 使用的内存被指示为 MMU 的禁止区域;
  • 每次故意访问 foo 时,访问该区域之前是允许的,之后是禁止的;
  • 添加了一个 MMU irq 处理程序来转储主机和负责违规的地址。

这实际上是某种观察点,但直接由代码本身自行处理。

现在,我想在 x86 平台上重用相同的技巧。问题是我离理解 MMU 在这个平台上是如何工作的,以及它是如何被 Linux 使用的,但我想知道是否已经存在任何库/工具/系统调用来处理这个问题。

请注意,我知道存在各种工具,如 Valgrind 或 GDB 来管理内存问题,但据我所知,这些工具都没有被调试代码动态重新配置。

我主要对 Linux 下的用户空间感兴趣,但也欢迎任何有关内核模式或 Windows 下的信息!

4

5 回答 5

5

您可以使用 mmap (MAP_ANONYMOUS) 和 mprotect 函数来操作虚拟内存系统并使用相应的保护标志。当然,您的变量需要限制为系统页面大小的倍数。许多小变量将带来巨大的开销。

当然,在管理对内存区域的访问权限时,您的应用程序需要正常工作。您还需要对受保护区域使用 mmap() 而不是 malloc。

这是 MMU 的用户空间接口层,以相对可移植的方式。

mmapmprotect

于 2010-04-30T18:37:23.160 回答
2

两个不错的选择:

  • dmalloc是一个库,它取代malloc()free()具有广泛的调试版本,能够使用页面边界来检测内存溢出/欠载、填充分配和释放的内存、泄漏检查等。
  • valgrind是一个内存调试器,它允许非常精确的内存调试(准确地检测任何越界访问),但会牺牲程序速度(程序在其下运行速度要慢得多)。它还可以进行泄漏检查。
于 2010-04-30T18:51:30.993 回答
1

系统mprotect()调用就是您所追求的。这使您可以更改对内存区域的保护。

Linux 下 x86 上的内存保护是在页面级别完成的 - 4096 字节。因此,您必须安排受保护的变量存在于其自己的页面上,而不是与任何其他变量共享。一种安排方法是使用posix_memalign()为变量分配内存,使用 4096 作为对齐并将大小四舍五入到 4096 的下一个倍数(实际上,您可以使用sysconf(_SC_PAGESIZE)可移植的方式确定页面大小,而不是而不是使用硬编码值)。另一种方法是在联合中分配变量,将其填充到页面大小的倍数,并使用 gcc 属性__attribute__ ((aligned (4096))来对齐变量。

代替您的 MMU IRQ 处理程序,您只需SIGSEGV使用sa_sigaction传递给sigaction()函数的结构成员为信号安装一个信号处理程序。您的信号处理程序将传递一个siginfo_t结构作为其第二个参数,该结构将包含一个sa_addr具有错误指令地址的成员。

于 2010-05-01T05:39:33.090 回答
1

我认为您能做的最好的事情就是启动一个看门狗线程,该线程保留该值的副本并不断将其副本与工作值进行比较。您将无法准确捕获该值何时被覆盖,但您会在所需的任何粒度内收到通知(即,如果您将线程设置为每 10 毫秒检查一次,您将在 10 毫秒内收到通知)。

于 2010-04-30T19:38:49.987 回答
0

电围栏有点旧,但仍然维护和有用。许多人将其作为更复杂调试的起点。它非常容易修改。

我也是 Valgrind 的忠实粉丝,但 Valgrind 并非在所有平台上都可用。

于 2010-05-01T03:31:49.760 回答