⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 001_arch_i386_mm_fault_.html

📁 重读linux 2.4.2o所写的笔记
💻 HTML
📖 第 1 页 / 共 3 页
字号:
             * We need the page table lock to synchronize with
        kswapd<br>
        &nbsp;&nbsp; &nbsp; * and the SMP-safe atomic PTE updates.<br>
        &nbsp;&nbsp; &nbsp; */<br>
        &nbsp;&nbsp; &nbsp;spin_lock(&amp;mm-&gt;page_table_lock);<br>
        &nbsp;&nbsp; &nbsp;entry = *pte;<br>
        &nbsp;&nbsp; &nbsp;if (!pte_present(entry)) { //pte不存在,映射有问题,又分为两种情况<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/*<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; * If it truly wasn't present, we
        know that kswapd<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; * and the PTE updates will not
        touch it later. So<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; * drop the lock.<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; */<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
        &nbsp;spin_unlock(&amp;mm-&gt;page_table_lock);<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (pte_none(entry))&nbsp;
        //第一种情况:根本没有建立,或者已经被断开<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return
        do_no_page(mm, vma, //页面不存在, 就是没有,或者被try_to_swap_out<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        address,&nbsp; // 断开, 这种页可以属于page cache<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        write_access,<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        pte&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 参见filemap_nopage 了解page cache
        的换入<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        );<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        return do_swap_page(mm, vma,&nbsp; //第二种情况: not present,
        那么就属于swapper_space管理<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        address, pte,<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        pte_to_swp_entry(entry),<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        write_access<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        );<br>
        &nbsp;&nbsp; &nbsp;}<br>
        <br>
        &nbsp;&nbsp;&nbsp; //如果是read 时产生陷入或者时pte 的映射问题<br>
        &nbsp;&nbsp;&nbsp; //或者是一个非法的操作, 已经在do_page_fault 过滤掉了<br>
        &nbsp;&nbsp; &nbsp;if (write_access) { //由于页面写保护产生的陷入, 而OS 却容许用户写入<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (!pte_write(entry))<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return
        do_wp_page( mm, //就是处理COW 的第二步<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        vma, //Copy on Write<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        address, //第一步是建立一个不容许写的页<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        pte, entry //却在vma 中赋予用户写的权限<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        );<br>
        <br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;entry = pte_mkdirty(entry);<br>
        &nbsp;&nbsp; &nbsp;}<br>
        &nbsp;&nbsp; &nbsp;entry = pte_mkyoung(entry);<br>
        &nbsp;&nbsp; &nbsp;establish_pte(vma, address, pte, entry);<br>
        &nbsp;&nbsp; &nbsp;spin_unlock(&amp;mm-&gt;page_table_lock);<br>
        &nbsp;&nbsp; &nbsp;return 1;<br>
        }<br>
        <br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里要强调的是页面的换入.
        有以下途经分配/换入页面,从而建立页面<br>
        &nbsp;&nbsp;&nbsp;&nbsp; 映射.<br>
        &nbsp;&nbsp;&nbsp;&nbsp; I)第一种情况:根本没有建立,或者已经被断开.<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 换入函数 do_no_page(mm/memory.c),
        首先尝试 vma-&gt;vm_ops-&gt;nopage,<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        如果vma没有提供nopage操作就使用do_anonymous_page分配一个空闲页面.<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (本次分析细节到此结束)<br>
        &nbsp;&nbsp;&nbsp;&nbsp; II)第二种情况是被交换到了swap space<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 则通过 do_swap_page从swap
        文件读入内存(或者从swap cache 找回).<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 此函数还涉及计COW, 这里不再讨论.<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 页面的释放和换出这里页简单提提,首先定义匿名页面是<br>
        page-&gt;mapping(address mapping)为NULL的页面.页面换出当然是try_to_swap_out<br>
        所为 .try_to_swap_out换出非匿名页的时候是直接断开页面映射.匿名的clean页<br>
        面的映射也是直接断开,因为不需要写入交换文件.<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果是dirty的匿名页,则分配一个swap页(swap
        file中的一个页面)然后将<br>
        swap 页的entry写入pte,并置pte为页面不在内存.<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
        &nbsp;&nbsp;&nbsp; try_to_swap_out区别对待这三种页面,和 handle_pte_fault换入页面的不同<br>
        操作相对应.<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
        &nbsp;&nbsp; 总结一下页面的周转:从try_to_swap_out和handle_pte_fault看过去, 换<br>
        出要不就是swap
        space,要不就是page-&gt;mapping-&gt;a_ops-&gt;writepage(见mm/vmscan.c<br>
        函数page_launder,应该注意到无论是swap cache还是page cahche都使用writepage<br>
        换出页面).换入要不就是swap space,要不就是vma-&gt;vm_ops-&gt;nopage(分配干净页面<br>
        就不算进页面周转了).<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
        &nbsp;&nbsp; 下面的问题就是 page-&gt;mapping-&gt;a_ops-&gt;writepage 和
        vma-&gt;vm_ops-&gt;nopage<br>
        到底是什么函数,怎样赋值?<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
        先看page-&gt;mapping-&gt;a_ops-&gt;writepage,搜索page-&gt;mapping,在函数<br>
        do_generic_file_read(mm/filemap.c)中发现page-&gt;mapping来源于<br>
        inode-&gt;i_mapping. do_generic_file_read-&gt;__add_to_page_cache读入一个页面的<br>
        文件后,将页面加入page cache,同时赋予page-&gt;mapping以addr space.&nbsp; 另外在做搜<br>
        索的过程中应该注意函数add_to_page_cache_locked(mm/filemap.c)此函数建立page<br>
        cache内页面的page-&gt;mapping映射.搜索调用add_to_page_cache_locked的函数得知,<br>
        shmem_nopage(mm/shmem.c)建立的page-&gt;mapping来源于inode;add_to_swap_cache<br>
        (mm/swap_state.c)建立的的page-&gt;mapping映射是swapper_space(也在swap_state.c).<br>
        顺着这些线索,可以找到,其实写页面最终和一个inode相关联,这也于理相符. 我们推<br>
        断换入用的vma-&gt;vm_ops-&gt;nopage最终也和inode相关.<br>
        &nbsp;&nbsp; 看看vma-&gt;vm_ops-&gt;nopage的情况. 直接搜索nopage,发现有两种vm_ops,<br>
        filemap_nopage(* area,address, no_share)(mm/filemap.c), shmem_nopage( *
        vma,<br>
        address, no_share)(mm/shmem.c).<br>
        &nbsp;&nbsp;&nbsp; 现在看来,vma可以获取文件映射(mmap,参考函数generic_file_mmap),shemem,<br>
        或者匿名页,来建立其终物理页面的映射.从这些线索分析,filemap_nopage利用<br>
        page-mapping的readpage从文件读入页面内容,呼应了刚才的猜想.shmem_nopage<br>
        只是通过vma相关联的文的inode之mapping在swap space寻找被交换出去的shemem<br>
        页面,并不用来从文件读取页面内容.寻找到的页面(或者新分配的)就加入page cache<br>
        (如果是从swap cache找到的则需要从swap chache移出).到这里再看page cache和<br>
        swap cache的界定,page-&gt;maping的值如果是swapper_space, 则页面处于swap cache,<br>
        如果page-&gt;maping的值是其他add space,比如filemap, shemem设置的mapping,则称<br>
        页面在page cache 中.<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
        &nbsp;&nbsp; 希望还没有迷路.<br>
        <br>
        <br>
        2. asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long
        error_code)<br>
        <br>
        &nbsp;&nbsp; 不是想在这里详细介绍i386 cpu的处理机制,而是给出中断处理在linux中的<br>
        线索,以资参考。<br>
        <br>
        &nbsp;&nbsp; 中断或异常发生后,i386终止执行当前运行的指令流(参考:),保存必要的<br>
        状态根据当前的运行级别(内核/用户),从idt选择合适的gate,执行指定地址<br>
        的处理函数。<br>
        &nbsp;&nbsp; 我们以页面异常为例。<br>
        <br>
        &nbsp;&nbsp; 首先看页面异常门的设置。首先要看idt地址。在系统启动的时候,boot程序已<br>
        经初始化了一个idt,但是在kernel中,还要重新指定定idt地址并用lidt加载内核<br>
        的idt。从 arch/i386/kernel/traps.c&nbsp; 的函数trap_init 看过去 .<br>
        宏 set_trap_gate:<br>
        <br>
        static void __init set_trap_gate(unsigned int n, void *addr)<br>
        {<br>
        &nbsp;&nbsp; &nbsp;_set_gate(idt_table+n,15,0,addr);<br>
        }<br>
        <br>
        &nbsp;&nbsp; 引用了idt地址, idt_table,定义在traps.c 文件的开始 处:<br>
        &nbsp; &nbsp;<br>
        <br>
        /*<br>
        &nbsp;* The IDT has to be page-aligned to simplify the Pentium<br>
        &nbsp;* F0 0F bug workaround.. We have a special link segment<br>
        &nbsp;* for this.<br>
        &nbsp;*/<br>
        struct desc_struct idt_table[256]
        __attribute__((__section__(".data.idt")))= { {0, 0}, };<br>
        <br>
        <br>
        <br>
        &nbsp;&nbsp;&nbsp; 由此得知在内核链接的时候预留了一个section&nbsp; .data.idt 作为idt表.<br>
        从init/main.c 的函数start_kernel开始内核 初始化经历 -&gt;trap_init-&gt;cpu_init:<br>
        &nbsp;&nbsp;&nbsp; __asm__ __volatile__("lidt %0": "=m" (idt_descr));<br>
        &nbsp;&nbsp; &nbsp;<br>
        &nbsp;&nbsp;&nbsp; 至此,trap初始化,idt表设置已经完成. 深入下去的话include/asm-i386/desc.h<br>
        中定义:<br>
        &nbsp;&nbsp;&nbsp; #define idt_descr (*(struct Xgt_desc_struct *)((char
        *)&amp;idt - 2))<br>
        &nbsp;&nbsp;&nbsp; 并声明<br>
        &nbsp;&nbsp;&nbsp; extern struct desc_struct *idt, *gdt;<br>
        &nbsp;&nbsp;&nbsp; 而idt是编译链接程序生成的符号,地址即是.data.idt<br>
        <br>
        &nbsp; &nbsp;<br>
        &nbsp;&nbsp;&nbsp; 函数trap_init 中 初始化14号异常,即页面异常入口为page_fault<br>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        set_trap_gate(14,&amp;page_fault);<br>
        <br>
        &nbsp;&nbsp;&nbsp; page_falut定义在arch/i386/kernel/entry.s:<br>
        <br>
        ENTRY(page_fault)<br>
        &nbsp;&nbsp; &nbsp;pushl $ SYMBOL_NAME(do_page_fault)<br>
        &nbsp;&nbsp; &nbsp;jmp error_code<br>
        <br>
        &nbsp;&nbsp;&nbsp;&nbsp; 在这里调用页面异常处理函数
        do_page_fault(arch/i386/mm/fault.c).<br>
        &nbsp;&nbsp;&nbsp;&nbsp; 下面分析此函数, 分析在代码中以注释形式出现.<br>
        /*<br>
        &nbsp;* 页面faults(故障) 处理入口.&nbsp; 主要任务时确定异常<br>
        &nbsp;* 发生的地址和原因,然后把不同的故障传入不同<br>
        &nbsp;* 的入口函数.<br>
        &nbsp;*<br>
        &nbsp;* error_code:<br>
        &nbsp;*&nbsp;&nbsp; &nbsp;bit 0 == 0 means no page found, 1 means
        protection fault<br>
        &nbsp;*&nbsp;&nbsp; &nbsp;bit 1 == 0 means read, 1 means write<br>
        &nbsp;*&nbsp;&nbsp; &nbsp;bit 2 == 0 means kernel, 1 means user-mode<br>
        &nbsp;*<br>
        &nbsp;*&nbsp; 有三种情况下陷入此函数:<br>
        &nbsp;*&nbsp;&nbsp;&nbsp; 1. pmd, pgt, pte 有一个为空, 即未建立映射或已经撤销.<br>
        &nbsp;*&nbsp;&nbsp;&nbsp; 2. 页面不在内存, 即,为内核交换到了磁盘.<br>
        &nbsp;*&nbsp;&nbsp;&nbsp; 3. 权限不正确.<br>
        &nbsp;*&nbsp;&nbsp; &nbsp;<br>
        &nbsp;*&nbsp;&nbsp;&nbsp; 情况1. 此种页面属于已经撤销的, 此种页面由page cache
        (address_space)管理.<br>
        &nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        try_to_swap_out 把这种页面的映射断开, 即,把相应的pte 置成0 .<br>
        &nbsp;*&nbsp; &nbsp;<br>
        &nbsp;*&nbsp;&nbsp;&nbsp; 情况2. 中的页面属于swapper_space 管理. try_to_swap_out
        不会把这种 pte<br>
        &nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 置0,
        而会换成相应的swp_entry_t.<br>
        &nbsp;*&nbsp; &nbsp;<br>
        &nbsp;*&nbsp;&nbsp;&nbsp; 转交下一级函数处理时, 所有非法操作都在这个函数中<br>
        &nbsp;*&nbsp;&nbsp;&nbsp; 处理掉了<br>
        &nbsp;*/&nbsp;&nbsp; &nbsp;<br>
        asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long
        error_code)<br>
        {<br>
        &nbsp;&nbsp; &nbsp;struct task_struct *tsk;<br>
        &nbsp;&nbsp; &nbsp;struct mm_struct *mm;<br>
        &nbsp;&nbsp; &nbsp;struct vm_area_struct * vma;<br>
        &nbsp;&nbsp; &nbsp;unsigned long address;<br>
        &nbsp;&nbsp; &nbsp;unsigned long page;<br>
        &nbsp;&nbsp; &nbsp;unsigned long fixup;<br>
        &nbsp;&nbsp; &nbsp;int write;<br>
        &nbsp;&nbsp; &nbsp;siginfo_t info;<br>
        <br>
        &nbsp;&nbsp; &nbsp;/* 确定异常发生的地址*/<br>
        &nbsp;&nbsp; &nbsp;__asm__("movl %%cr2,%0":"=r" (address));<br>
        <br>
        &nbsp;&nbsp; &nbsp;tsk = current;<br>
        <br>
        &nbsp;&nbsp; &nbsp;/*<br>
        &nbsp;&nbsp; &nbsp; * 由于demand 我们陷入了内核虚拟空间. 我们使用<br>
        &nbsp;&nbsp; &nbsp; * 的 page table 是init_mm.pgd.<br>
        &nbsp;&nbsp; &nbsp; *<br>
        &nbsp;&nbsp; &nbsp; * NOTE! We MUST NOT take any locks for this case. We
        may<br>
        &nbsp;&nbsp; &nbsp; * be in an interrupt or a critical region, and
        should<br>
        &nbsp;&nbsp; &nbsp; * only copy the information from the master page
        table,<br>
        &nbsp;&nbsp; &nbsp; * nothing more.<br>
        &nbsp;&nbsp; &nbsp; */<br>
        &nbsp;&nbsp; &nbsp;if (address &gt;= TASK_SIZE)<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto vmalloc_fault;&nbsp;
        //异常发生于内核空间<br>
        <br>
        &nbsp;&nbsp; &nbsp;mm = tsk-&gt;mm;<br>
        &nbsp;&nbsp; &nbsp;info.si_code = SEGV_MAPERR;<br>
        <br>
        &nbsp;&nbsp; &nbsp;/*<br>
        &nbsp;&nbsp; &nbsp; * 如果异常发生在中断中或者没有用户<br>
        &nbsp;&nbsp; &nbsp; * context(环境), we must not take the fault..<br>
        &nbsp;&nbsp; &nbsp; */<br>
        &nbsp;&nbsp; &nbsp;if (in_interrupt() || !mm)<br>
        &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto no_context;<br>
        <br>
        &nbsp;&nbsp; &nbsp;down(&amp;mm-&gt;mmap_sem);<br>
        <br>
        &nbsp;&nbsp;&nbsp; //下面的主要思路是根据异常发生的地址和vma 的<br>
        &nbsp;&nbsp;&nbsp; //关系,分成几种不同情况进行处理<br>
        &nbsp;&nbsp; &nbsp;<br>
        &nbsp;&nbsp; &nbsp;vma = find_vma(mm, address); // 试着找一个vma , 其结束地址大于异常点<br>
        &nbsp;&nbsp; &nbsp;if (!vma)<br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -