缺页异常

 页式管理机制通过页面目录,页面表,将每一个线性地址(虚拟地址)转换成物理地址,但并不是每一次CPU都能访问到相应的物理内存单元,因此这样映射便失败了,会产生缺页异常;


页错误,又叫页缺失,计算机系统术语,是指在引入分页机制的操作系统中,一个进程的代码和数据被放置在一个虚拟的地址空间中,地址空间按固定长度划分为好多。同时,物理内存也按固定长度划分为好多

因为 物理内存小而 硬盘空间大,为了在内存里放置更多的 进程操作系统的设计者们决定把页映射到内存帧或硬盘上的 虚拟内存文件中。
进程的可视范围是它自己的 地址空间,它并不知道某一页映射到内存里还是 硬盘上,进程只管自己运行。当 进程需要访问某一页时, 操作系统通过查看分页表,得知被请求的页在内存里还是 硬盘里。若在内存里,则进行地址翻译;若在 硬盘里,则发生 页缺失操作系统立即阻塞该 进程,将 硬盘里对应的页换入内存,然后使该进程就绪(可以继续运行)。


首先明确下什么是缺页异常,CPU通过地址总线可以访问连接在地址总线上的所有外设,包括物理内存、IO设备等等,但从CPU发出的访问地址并非是这些外设在地址总线上的物理地址,而是一个虚拟地址,由MMU将虚拟地址转换成物理地址再从地址总线上发出,MMU上的这种虚拟地址和物理地址的转换关系是需要创建的,并且MMU还可以设置这个物理页是否可以进行写操作,当没有创建一个虚拟地址到物理地址的映射,或者创建了这样的映射,但那个物理页不可写的时候,MMU将会通知CPU产生了一个缺页异常。

下面总结下缺页异常的几种情况:

1、当MMU中确实没有创建虚拟页物理页映射关系,并且在该虚拟地址之后再没有当前进程的线性区vma的时候,可以肯定这是一个编码错误,这将杀掉该进程;

2、当MMU中确实没有创建虚拟页物理页映射关系,并且在该虚拟地址之后存在当前进程的线性区vma的时候,这很可能是缺页异常,并且可能是栈溢出导致的缺页异常;

3、当使用malloc/mmap等希望访问物理空间的库函数/系统调用后,由于linux并未真正给新创建的vma映射物理页,此时若先进行写操作,将如上面的2的情况产生缺页异常,若先进行读操作虽也会产生缺页异常,将被映射给默认的零页(zero_pfn),等再进行写操作时,仍会产生缺页异常,这次必须分配物理页了,进入写时复制的流程;

4、当使用fork等系统调用创建子进程时,子进程不论有无自己的vma,“它的”vma都有对于物理页的映射,但它们共同映射的这些物理页属性为只读,即linux并未给子进程真正分配物理页,当父子进程任何一方要写相应物理页时,导致缺页异常的写时复制;

目前来看,应该就是这四种情况,还是比较清晰的,可发现一个重要规律就是,linux是直到实在不行的时候才会分配物理页




<think>好的,用户的问题是关于如何注册钩子函数来追踪处理缺页异常(Page Fault Exception)。首先,我需要回忆一下操作系统中的异常处理机制,特别是缺页异常的相关知识。缺页异常通常发生在内存管理中,当程序访问的虚拟地址没有对应的物理页,或者权限不足时触发。用户想要注册钩子函数来追踪这类异常,可能是在调试或性能分析时用到。 接下来,我得考虑不同的操作系统环境。用户没有指定具体系统,所以可能需要涵盖Linux和Windows的情况。对于Linux,我记得可以通过修改内核模块或者使用调试工具来捕获缺页异常。例如,Linux内核提供了诸如register_page_fault_notifier这样的函数,或者可以通过修改do_page_fault函数来添加钩子。此外,用户空间的话可能需要使用信号处理,比如SIGSEGV信号,但缺页异常通常在内核处理,用户空间的信号可能不够底层。 然后是Windows方面,Windows提供了Vectored Exception Handling(VEH)机制,可以注册异常处理程序。此外,驱动程序开发中可能使用Filter Driver来监控异常,但这需要Windows Driver Kit(WDK)的知识,属于内核模式编程。 还需要考虑安全性和稳定性,因为注册钩子函数通常需要内核权限,可能会影响系统稳定性,甚至引入安全风险。所以需要提醒用户谨慎操作,并确保有必要的权限和备份措施。 另外,参考用户提供的引用,其中提到configUSE_MUTEXES和内存分配失败钩子函数,这可能涉及到FreeRTOS之类的实时操作系统,但用户的问题更偏向于通用操作系统如Linux或Windows的缺页异常处理,所以可能需要区分不同的系统环境。 最后,我需要总结步骤,分点说明不同系统下的方法,并提醒注意事项,确保回答结构清晰,步骤详细,同时生成相关问题供用户进一步学习。</think>### 如何注册钩子函数追踪缺页异常缺页异常(Page Fault Exception)通常由内存访问错误触发,例如访问未映射的虚拟地址或权限不足的页面。注册钩子函数追踪此类异常需结合操作系统提供的机制,具体方法如下: --- #### **1. Linux 内核模块方法** 在 Linux 内核中,可通过以下步骤注册钩子: - **修改缺页异常处理函数** Linux 内核的缺页异常处理入口为 `do_page_fault`(位于 `arch/x86/mm/fault.c`)。通过内核模块修改此函数指针,插入自定义的钩子逻辑: ```c static asmlinkage void (*original_do_page_fault)(struct pt_regs *regs, unsigned long error_code); static void custom_do_page_fault(struct pt_regs *regs, unsigned long error_code) { // 记录触发缺页的地址:CR2 寄存器存储了引发异常的地址 unsigned long fault_address = read_cr2(); printk("Page fault at 0x%lx\n", fault_address); original_do_page_fault(regs, error_code); } // 模块加载时替换函数指针 static int __init init_module(void) { original_do_page_fault = (void *)kallsyms_lookup_name("do_page_fault"); *(unsigned long *)kallsyms_lookup_name("do_page_fault") = (unsigned long)custom_do_page_fault; return 0; } ``` 注意:需禁用内核写保护(`CR0.WP` 位)以修改内核代码段[^3]。 - **使用 `register_page_fault_notifier`** 某些内核版本支持注册缺页通知链,允许在缺页发生时回调自定义函数: ```c static struct notifier_block pf_notifier = { .notifier_call = page_fault_callback, }; static int page_fault_callback(struct notifier_block *self, unsigned long val, void *data) { // 通过 data 获取异常上下文 return NOTIFY_DONE; } // 注册通知链 register_page_fault_notifier(&pf_notifier); ``` --- #### **2. Windows 驱动开发方法** 在 Windows 中,可通过 **Vectored Exception Handling (VEH)** 或 **内核驱动** 捕获异常: - **VEH(用户态)** 使用 `AddVectoredExceptionHandler` 注册异常处理函数: ```cpp LONG CALLBACK VectoredHandler(PEXCEPTION_POINTERS ExceptionInfo) { if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { // 通过 ExceptionInfo->ExceptionRecord->ExceptionInformation[1] 获取触发地址 } return EXCEPTION_CONTINUE_SEARCH; } // 注册钩子 AddVectoredExceptionHandler(1, VectoredHandler); ``` 注意:VEH 仅能捕获用户态异常,内核态缺页需通过驱动实现[^1]。 - **内核驱动(内核态)** 通过注册 **异常回调**(如 `KeRegisterBoundCallback`)或拦截中断描述符表(IDT)中的缺页异常入口(例如 `#PF` 中断号为 14): ```cpp // 替换 IDT 表项 void HookPageFaultHandler() { IDT_ENTRY* idt = (IDT_ENTRY*)getIdtBase(); OriginalPageFaultHandler = idt[14].Offset; idt[14].Offset = (ULONG)CustomPageFaultHandler; } ``` --- #### **3. 注意事项** - **权限与稳定性**:内核钩子需 `root`/管理员权限,且可能引发系统崩溃。 - **性能影响**:频繁的缺页追踪会显著降低系统性能。 - **调试工具替代方案**:可使用 `perf`(Linux)或 ETW(Windows)进行无侵入式监控。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值