截获Linux操作系统异常处理
作者:网络转载 发布时间:[ 2013/5/13 10:24:57 ] 推荐标签:
我仿照着写了一个,名为my_page_fault:
asmlinkage void my_page_fault(void);
asm(" .text");
asm(" .type my_page_fault,@function");
asm("my_page_fault:");
//the first 3 bytes of the routine basically do nothing,
//but I decide to keep them because kernel may rely on them for some special purpose
asm(" .byte 0x66");
asm(" xchg %ax, %ax");
asm(" callq *addr_adjust_exception_frame");
asm(" sub $0x78, %rsp");
asm(" callq *addr_error_entry");
asm(" mov %rsp, %rdi");
asm(" mov 0x78(%rsp), %rsi");
asm(" movq $0xffffffffffffffff, 0x78(%rsp)");
asm(" callq my_do_page_fault");
asm(" jmpq *addr_error_exit");
asm(" nopl (%rax)");
其中第9行addr_adjust_exception_frame是(pv_irq_ops+0x30)地址处存储的值;第11行addr_error_entry是error_entry的地址;第16行addr_error_exit是error_exit的地址。这几个值需要从System.map文件中查询,然后用内核模块参数的形式传入。而my_do_page_fault则是我们自己定义的page fault处理函数。
如果需要截获X86_32的page fault,可以参考这个C文件。不过需要注意的是,新版内核有所变动,这里的代码需要根据自己的情况做一些调整。
有了自定义的ISR之后,可以将这个ISR填到IDT中,加载新的IDT表之后,自定义的page fault处理函数开始发挥作用了。这个过程主要有以下几个步骤:
用store_idt(&default_idtr)保存现有的IDT寄存器值
从default_idtr中读出IDT表首地址和表的大小
申请一个页面
将原来的idt表拷贝到新申请的页面中
利用pack_gate将my_page_fault(注意不是my_do_page_fault)填入到对应的IDT项中
在idtr中填写新的IDT表地址和大小,用load_idt(&idtr)加载新的IDT表到当前CPU
利用smp_call_function,将新的IDT表加载到其他CPU上。
如果想恢复原来的IDT表,则用load(&default_idtr)和smp_call_function加载原来的IDT表,释放申请的页面。
读完文章之后,可以参考我的github中的代码:https://github.com/RichardUSTC/intercept-page-fault-handler
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11