linux中的mprotect
如果我linux中的mprotect,linux,copy-on-write,mprotect,Linux,Copy On Write,Mprotect,如果我mprotect一个没有PROT\u的段,如果SIGSEGV由于sigaction和sa\u sigaction处理的写入而发生,我们将能够使用sigainfo\u t的si\u addr>找到故障发生的地址。但是,有没有办法找到要写入的数据和数据长度 我之所以尝试这样做,是因为我正在为我的项目尝试一种写时拷贝机制 您找不到进程试图写入的数据,询问其大小也没有意义。如果你能得到数据,那就意味着内核已经在某处复制了它 您在整个页面上获得一个SIGSEGV。也就是说,无论进程写入的数据是什么,
mprotect
一个没有PROT\u的段,如果SIGSEGV
由于sigaction
和sa\u sigaction
处理的写入而发生,我们将能够使用sigainfo\u t
的si\u addr>找到故障发生的地址。但是,有没有办法找到要写入的数据和数据长度
我之所以尝试这样做,是因为我正在为我的项目尝试一种写时拷贝机制 您找不到进程试图写入的数据,询问其大小也没有意义。如果你能得到数据,那就意味着内核已经在某处复制了它
您在整个页面上获得一个SIGSEGV
。也就是说,无论进程写入的数据是什么,每页都会出现一个错误——第一次尝试写入一个字节时。因此,您需要做的就是:
- 跟踪页面状态
- 根据需要增加权限
您找不到进程试图写入的数据,询问其大小也没有意义。如果你能得到数据,那就意味着内核已经在某处复制了它
您在整个页面上获得一个
SIGSEGV
。也就是说,无论进程写入的数据是什么,每页都会出现一个错误——第一次尝试写入一个字节时。因此,您需要做的就是:
- 跟踪页面状态
- 根据需要增加权限
内核不知道,因此无法告诉您。但是如果你想的话,你可以试试看。您拥有堆栈上出现故障的代码地址,因此您可以在那里反汇编代码以尝试找出它。没有其他方法可以知道(如果你不清楚原因,请想一想)。该指令出现故障,因为它触及了受保护的页,除非您分析汇编代码,否则这就是已知的全部
如果你不能通过只知道出现错误的页面来判断你在处理什么对象,我强烈建议你重新考虑改变你的设计。(
posix_memalign
,也许吧?)
更新:不要忘记,您需要在每个上下文切换上调用一个钩子。您可能需要在每个钩子上复制页面。例如:
上下文A使用CoW语义访问页面Q。上下文A以只读方式访问该页
上下文B使用CoW语义访问页面Q。上下文B以只读方式访问该页
上下文A去修改页面,我们为上下文B创建一个副本。上下文A现在拥有对页面的写访问权并修改它
我们从上下文A切换到上下文B。此时,您必须切换为上下文B制作的页面副本
请注意,另一种解决方法是让上下文对映射和锁定页面进行特定调用。如果您允许一个上下文在一个上下文开关上保存映射,那么这是行不通的——至少,如果没有大量额外的工作,这是行不通的。内核不知道,所以它不能告诉您。但是如果你想的话,你可以试试看。您拥有堆栈上出现故障的代码地址,因此您可以在那里反汇编代码以尝试找出它。没有其他方法可以知道(如果你不清楚原因,请想一想)。该指令出现故障,因为它触及了受保护的页,除非您分析汇编代码,否则这就是已知的全部
如果你不能通过只知道出现错误的页面来判断你在处理什么对象,我强烈建议你重新考虑改变你的设计。(posix_memalign
,也许吧?)
更新:不要忘记,您需要在每个上下文切换上调用一个钩子。您可能需要在每个钩子上复制页面。例如:
上下文A使用CoW语义访问页面Q。上下文A以只读方式访问该页
上下文B使用CoW语义访问页面Q。上下文B以只读方式访问该页
上下文A去修改页面,我们为上下文B创建一个副本。上下文A现在拥有对页面的写访问权并修改它
我们从上下文A切换到上下文B。此时,您必须切换为上下文B制作的页面副本
请注意,另一种解决方法是让上下文对映射和锁定页面进行特定调用。如果允许上下文在上下文开关之间保存映射,那么这是行不通的——至少,如果没有大量额外的工作,这是行不通的。使用mprotect()时,您知道要保护的内存段的起始地址和长度。您需要将该信息存储在某个位置,以便以后使用
一旦您保护了内存段,如果您以违反保护的方式访问它,您将得到SIGSEGV信号。在信号处理程序中,您将获得指向siginfo\u t的指针。这将为您提供所需的信息。si\u addr提供了导致非法访问的指令的地址,而si\ptr为您提供了非法访问的地址。然后将si_ptr与受保护的内存段进行比较,直到找到它所属的内存段,这就是“写时复制”需要复制的内存段。。。完成后,需要调用setcontext()或siglongjmp()之类的函数,以便从已知位置继续运行
我希望这能有所帮助。使用mprotect()时,您知道要保护的内存段的起始地址和长度。您需要将该信息存储在某个位置,以便以后使用
一旦您保护了内存段,如果您以违反保护的方式访问它,您将得到SIGSEGV信号。在信号处理程序中,您将获得指向siginfo\u t的指针。这将为您提供所需的信息。si_addr为您提供导致非法访问的指令的地址,si_ptr为您提供被访问的地址