我正在编写一个框架来实现在模拟器和未修改的主机软件中运行的RTL的协同仿真.编写主机软件以控制实际硬件,通常以两种方式之一工作:
>通过驱动程序读/写呼叫
>使用mmap进行内存映射访问
前一种情况非常简单 – 编写一个库,它实现与驱动程序相同的读/写调用,并在运行模拟时与之相关联.这一切都非常有效,我可以运行未经修改的生产软件作为我的RTL模拟的刺激.
第二种情况比第一种情况要困难得多……
陷阱mmap
最初我以为我可以使用LD_PRELOAD来拦截mmap调用.在我的mmap实现中,我会分配一些页面对齐的内存,然后对其进行保护并设置一个信号处理程序来捕获SIGSEGV.
这种方法存在许多问题:
读取与写入
我可以从siginfo_t-> si_addr确定访问的地址,但不能确定访问是读还是写.
捕获重复访问
在信号处理程序中,我需要取消保护内存区域,否则只要我的处理程序退出并且主机代码永远不能继续,我就会重复SIGSEGV.但是,如果我取消保护区域,那么我的信号处理程序将不会捕获后续访问.
信号处理程序的肮脏
在模拟器驱动RTL并返回结果时阻塞信号处理程序违反了各种编程规则 – 特别是假设模拟器可以触发各种其他事件并在从此访问返回结果之前执行任意代码.
其他方法
我想知道是否可以创建一个类似文件的对象,其行为类似于磁盘而不是在缓冲区上使用mprotect.我没有找到任何表明这是可行的信息.
问题
是否可以捕获对mmap区域的所有访问以及如何?
>访问需要阻止一段不确定的时间(模拟器运行时)
>读取访问需要检索由我的陷阱放置的新值
假设LD_PRELOAD和mprotect是最佳路线:
>我可以确定访问是读取还是写入调用?
>我如何捕获后续访问,因为我必须取消保护该区域?
相关问题
解决方法
无论何时获得SIGTRAP,您都可以分析写入的值(如果是写访问权限),还可以重新保护页面以捕获将来的访问.
更正:如果读取和写入都有副作用,请先尝试只写保护,然后应用读取副作用并尝试只读保护,然后在最终的SIGTRAP处理程序中启用写入和处理写入的副作用.
更新:我推荐假设的只写保护是错误的,而大多数架构都没有这种保护.幸运的是,有一种更简单的方法可以知道失败的操作是否尝试读取内存,至少在x86上是这样:
页面错误异常将错误代码推送到堆栈,该错误代码在Linux SIGSEGV处理程序中作为sigcontext结构的错误成员提供.对于写入错误,Bit 1 of the error code为1,否则为0.对于读 – 修改 – 写操作,它最初将为0(这里你可以模拟读数,确切地知道它会发生).